【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;
}

浙公网安备 33010602011771号