题目
题目链接: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) 给出,要求 (0leq x_ileq a_i),(0leq y_ileq b_i))。
求最终最少能有多少个不同的二元组。输出方案。多测。
(sum nleq 2 imes 10^5),(0leq a_i,b_ileq 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(nlog 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<<"
";
for (int i=1;i<=n;i++)
cout<<x[i]<<" "<<y[i]<<"
";
}
int main()
{
int T=1;
scanf("%d",&T);
while (T--) Work();
return 0;
}