IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> CF751 C. Optimal Insertion -> 正文阅读

[数据结构与算法]CF751 C. Optimal Insertion

Problem - C - Codeforces

给定两个序列a和b,a不能动,b可任意重排,然后把b插入a中得到新序列c,求c的最小逆序对个数。

观察可以得到一个结论,依次把b往a插入,插入第一个b中元素时,如果把bi插在ps(i)中最优,那么一定有bi <= bj时, ps(i) <= ps(j)

简单证明:假设bi增大,然后它的最优位置反而左移,那么左边一定存在一些比当前bi大的值,左移过了这些值才能更优,但是原来bi更小,因此左移过这些值对之前也更优,矛盾。

得到这个性质之后,有每次插入ab两序列之间产生的逆序对数最小,且b本身不会产生逆序对,故只要对于每个bi,求出它在a内最优位置产生的逆序对数和,加上a本身的逆序对数,一定是最优解。

之后有两个做法:

较常规做法:

把a数组、b数组都按值排序。从小到大枚举b,同时维护一棵线段树,节点i表示b插入ai 与 ai - 1之间时的代价,一开始a都没有加进来,意味着当前每个a都是大于b的,那么节点i的值 = i-1。然后b增大了,一些大于b的元素变成了等于b,那么把这些元素往后的插入空隙在线段树上对应节点值-1;一些等于b的元素变成了小于b,那么这些元素往前的插入空隙在线段树上对应节点值+1,更改完后查询整棵线段树的最小值就是当前这个b插入最优位置产生的逆序对数。

题解做法:

之前的常规做法其实没怎么用到bi最优位置随bi增加而增加的这一条性质。题解中用了一种分治求解,即每次求中间的bi的最优位置,然后递归处理下一层,递归下去时bi左侧的b元素最优可能位置+bi右侧的b元素最优可能位置才等于当前层的个数,因此复杂度也是nlogn

代码:(第二种做法)

#include <bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define sc second
#define pb push_back
#define ll long long
#define trav(v, x) for(auto v:x)
#define VI vector<int>
#define VLL vector<ll>
//define double long double
#define all(x) (x).begin(),(x).end()
using namespace std;
const double eps = 1e-10;//1e-12
const int N = 2e6 + 100;
const ll mod = 998244353;//1e9 + 7;

int n, m, a[N], b[N], ans[N];
vector<int> hav[N];

void calc(int l, int r, int lp, int rp)
{
//	cerr << l << ' ' << r << ' ' << lp << ' ' << rp << '\n';
//	system("pause");
	int mid = (l + r) / 2;
	VI buk(rp - lp + 2, 0);
	for(int i = lp + 1; i <= rp; i++)
	{
		buk[i - lp] = buk[i - lp - 1];
		if(a[i - 1] > b[mid])
			++buk[i - lp];
	}
	//cerr << "!!" << '\n';
//	for(int i = lp; i <= rp; i++)
//		cerr << buk[i - lp] << ' ';
	//cerr << '\n';
	int mn = 1e9, res = -1, tmp = 0;
	for(int i = rp; i >= lp; i--)
	{
		if(i < rp && a[i] < b[mid])
			tmp++;
		int nw = buk[i - lp];
		nw += tmp;
	//	cerr << "??" << i << ' ' << nw << '\n';
		if(nw < mn)
			mn = nw, res = i;
	}
	ans[mid] = res;
	if(l == r)
		return;
	if(l < mid)calc(l, mid - 1, lp, res);
	if(mid < r)calc(mid + 1, r, res, rp);
}


int fen[N], num, val[N];

void upd(int x)
{
	for(; x <= num; x += x & (-x))
		fen[x]++;
}

int calc(int x)
{
	int res = 0;
	for(; x; x -= x & (-x))
		res += fen[x];
	return res;
}

void sol()
{
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
		cin >> a[i];
	for(int i = 1; i <= m; i++)
		cin >> b[i];
	sort(b + 1, b + m + 1);
	calc(1, m, 1, n + 1);
	for(int i = 1; i <= n + 1; i++)
		hav[i].clear();
	for(int i = 1; i <= m; i++)
	{
		hav[ans[i]].pb(b[i]);
	}
	num = 0;
	for(int i = 1; i <= n; i++)
	{
		trav(v, hav[i])
			val[++num] = v;
		val[++num] = a[i];
	}
	trav(v, hav[n + 1])
		val[++num] = v;
//	for(int i = 1; i <= num; i++)
//		cerr << val[i] << ' ';
//	cerr << '\n';
	sort(val + 1, val + num + 1);
	fill(fen, fen + num + 5, 0);
	ll res = 0;
	ll tot = 0;
	for(int i = 1; i <= n; i++)
	{
		trav(v, hav[i])
		{
			v = lower_bound(val + 1, val + num + 1, v) - val;
			res += tot - calc(v);
			upd(v), ++tot;
		}
		a[i] = lower_bound(val + 1, val + num + 1, a[i]) - val;
		res += tot - calc(a[i]);
		upd(a[i]), ++tot;
	}
	trav(v, hav[n + 1])
	{
		v = lower_bound(val + 1, val + num + 1, v) - val;
		res += tot - calc(v);
		upd(v), ++tot;
	}
	cout << res << '\n';
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	int tt;
	cin >> tt;
	while(tt--)
	{
		sol();
	}
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-28 12:36:29  更:2021-10-28 12:37:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:53:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码