D2. Dances (Hard Version) Codeforces Round 905 (Div. 2)

Problem - D2 - Codeforces

The main idea of ​​the question: There are two arrays a and b of length n, and a number m is given. Each operation must delete a number in a and b and then sort a and b in any order. It is required to use the minimum number of operations. For any i, there is a[i]<b[i], find the sum of the minimum number of operations when a[1]=1~m.

2<=n<=1e5.1<=m<=1e9;1<=a[i],b[i]<=1e9

Idea: First examine what is the optimal strategy for each operation. First of all, the numerical order must be that both arrays must be sorted from smallest to largest. If a is smaller than b, then the largest number in a and the smallest number in b should be deleted first. The number of numbers to be deleted can be enumerated dichotomously from 1 to n, because deleting more numbers is definitely easier to meet the conditions and comply with monotonicity. In this way, we get the answer when a[1] is fixed to a certain number.

        When we set a[1]=1, the answer is ans. When we increase a[1] to m, we can find that the difference is that a[1] does not need to be deleted before, but it needs to be deleted after it is increased. Then the answer is different. It is 0 or 1, and the number of operations increases as a[1] increases, so we can enumerate 1 to m in two to find the position of the answer + 1, that is, when we find an x ​​such that a[1]=x The answer obtained is different from ans, so the quantity in front * the quantity in the back of ans * (ans+1) is the final answer.

//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int N = 1e5 + 5;
ll n;
int a[N];
int temp[N];
int b[N];
bool check(int x)
{
	for (int i = 1; i <= n - x; i++)
	{
		if (a[i] >= b[x + i])
		{//a中的前n-x个数和b中后n-x个数做对比
			return 0;
		}
	}
	return 1;
}
void init()
{

}
void solve()
{
	cin >> n;
	int m;
	cin >> m;
	init();
	a[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		cin >> a[i];
		temp[i] = a[i];//复制一份a数组
	}
	for (int i = 1; i <= n; i++)
	{
		cin >> b[i];
	}
	sort(a + 1, a + n + 1);
	sort(b + 1, b + n + 1);//将a和b按从小到大的顺序排序
	int l = 0, r = n, mid;
	ll ans;
	while (l <= r)
	{//从1到n二分枚举操作次数
		mid = (l + r) >> 1;
		if (check(mid))
		{
			ans = mid;
			r = mid - 1;
		}
		else
		{
			l = mid + 1;
		}
	}
	l = 1, r = m;
	ll ans2 = m + 1;//初始化为m+1,没有枚举到答案不同的地方时,答案就是ans*m
	while (l <= r)
	{//二分枚举a[1],找到操作次数改变的第一个位置
		for (int i = 1; i <= n; i++)
		{
			a[i] = temp[i];
		}
		mid = (l + r) >> 1;
		a[1] = mid;
		sort(a + 1, a + n + 1);
		if (!check(ans))
		{
			ans2 = mid;
			r = mid - 1;
		}
		else
		{
			l = mid + 1;
		}
	}
	cout << (ans2-1)*ans+(m-ans2+1)*(ans+1);//两个操作次数分别乘以他们的数量
	cout << '\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	//t = 1;
	while (t--)
	{
		solve();
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/ashbringer233/article/details/134005948