【CF1607H】Banquet Preparations 2

题目

题目链接:https://codeforces.com/problemset/problem/1607/H
给定 \(n\) 个二元组 \((a_i,b_i)\),我们称两个二元组 \((a,b),(c,d)\) 相同,当且仅当 \(a=c\)\(b=d\)
对于第 \(i\) 个二元组,你需要让 \(a_i\) 减去 \(x_i\)\(b_i\) 减去 \(y_i\),且 \(x_i+y_i=m_i\)\(m_i\) 给出,要求 \(0\leq x_i\leq a_i\)\(0\leq y_i\leq b_i\))。
求最终最少能有多少个不同的二元组。输出方案。多测。
\(\sum n\leq 2\times 10^5\)\(0\leq a_i,b_i\leq 10^6\)

思路

两个二元组 \((a_i,b_i),(a_j,b_j)\) 可能相同,当且仅当 \(a_i+b_i-m_i=a_j+b_j-m_j\)
对于 \(a_i+b_i-m_i\) 都相同的一些二元组,考虑最少能把他们划分为多少个相同的二元组。
也就是问最少选择多少个满足 \(x+y=a_i+b_i-m_i\) 的点 \((x,y)\),满足所有二元组 \((a_i,b_i)\) 的左下方至少都有一个点。
直接按照 \(a\) 排序后贪心选就行了。
时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

const int N=2000010;
int n,ans,q[N],x[N],y[N];

struct node
{
	int a,b,m,id;
};
vector<node> a[N];

bool cmp(node x,node y)
{
	return x.a<y.a;
}

void Work()
{
	scanf("%d",&n);
	for (int i=1,x,y,z;i<=n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		a[x+y-z].push_back((node){x,y,z,i});
		q[i]=x+y-z;
	}
	ans=0;
	for (int i=1;i<=n;i++)
		if (a[q[i]].size())
		{
			sort(a[q[i]].begin(),a[q[i]].end(),cmp);
			for (int j=0,px=-1e9;j<(int)a[q[i]].size();j++)
			{
				node b=a[q[i]][j];
				if (b.b<q[i]-px) px=min(b.a,q[i]),ans++;
				x[b.id]=b.a-px; y[b.id]=b.m-x[b.id];
			}
			a[q[i]].clear();
		}
	cout<<ans<<"\n";
	for (int i=1;i<=n;i++)
		cout<<x[i]<<" "<<y[i]<<"\n";
}

int main()
{
	int T=1;
	scanf("%d",&T);
	while (T--) Work();
	return 0;
}
posted @ 2021-11-03 15:35  stoorz  阅读(135)  评论(0)    收藏  举报