Description
有X+Y+Z个三元组(x[i],y[i],z[i]),请你从每个三元组中挑数,并满足以下条件:
1、每个三元组中可以且仅可以选择一个数(即x[i],y[i],z[i]中的一个)
2、选择x[i]的三元组个数恰好为X
3、选择y[i]的三元组个数恰好为Y
4、选择z[i]的三元组个数恰好为Z问选出的数的和最大是多少
问选出的数的和最大是多少
Data Constraint
对于10%的数据满足,1<=X+Y+Z<=15
对于30%的数据满足,1<=X+Y+Z<=100
对于另外10%的数据满足,X=0
对于另外20%的数据满足,所有三元组中的x[i]=0
对于另外20%的数据满足,1<=X+Y+Z<=100000
对于100%的数据满足,1<=X+Y+Z<=500000,0<=x[i],y[i],z[i]<=500000
Solution
两个数很好做。但变成3个数呢?第4档部分分给了提示。我们将x[i],y[i],z[i]全部减去x[i],然后我们把y[i]-z[i]从大到小排序,枚举分界线,分界线以前的取y[]值的前Y大值,分界线以后的取z[]值的前Z大值。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=5e5+5,maxn1=1e6+10;
struct code{
ll x,y,z;
}a[maxn];
ll n,m,p,i,t,j,k,l,x,y,z,ans,mi,b[maxn],sum,bz[maxn1],num,ans1;
bool cmp(code x,code y){
return x.x>y.x;
}
ll get(){
char ch=getchar();ll x=0;
while (ch<48 || ch>57) ch=getchar();
while (ch>=48 && ch<=57) x=x*10+ch-48,ch=getchar();
return x;
}
int main(){
freopen("triple.in","r",stdin);freopen("triple.out","w",stdout);
scanf("%lld%lld%lld",&n,&m,&p);
for (i=1;i<=n+m+p;i++)
scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z),ans1+=a[i].x,a[i].y-=a[i].x-maxn,a[i].z-=a[i].x-maxn,a[i].x=a[i].y-a[i].z;
sort(a+1,a+n+m+p+1,cmp);mi=1e9;
for (i=1;i<=n+m+p;i++){
b[i]=b[i-1];
if (num<m) bz[a[i].y]++,mi=min(mi,a[i].y),b[i]+=a[i].y,num++;
else if (mi<a[i].y){
bz[mi]--;bz[a[i].y]++;b[i]+=a[i].y-mi;
while (!bz[mi]) mi++;
}
}
memset(bz,0,sizeof(bz));mi=1e9;num=0;sum=0;
for (i=n+m+p;i>=1;i--){
if (num<p) bz[a[i].z]++,mi=min(mi,a[i].z),sum+=a[i].z,num++;
else if (mi<a[i].z){
bz[mi]--;bz[a[i].z]++;sum+=a[i].z-mi;
while (!bz[mi]) mi++;
}
if (i>m && num==p) ans=max(ans,b[i-1]+sum);
}
ans+=ans1-maxn*(m+p);
printf("%lld\n",ans);
}