【NOIP2017提高A组集训10.28】三元组
(File IO): input:triple.in output:triple.out
Time Limits: 700 ms Memory Limits: 524288 KB
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问选出的数的和最大是多少
问选出的数的和最大是多少
Input
第一行三个非负整数分别表示X,Y,Z
接下来X+Y+Z行每行三个非负整数描述一个三元组(x[i],y[i],z[i])
Output
一行一个整数表示选出的数的和最大是多少
Sample Input
输入1:
1 2 1
2 4 4
3 2 1
7 6 7
5 2 3
输入2:
3 3 2
16 17 1
2 7 5
2 16 12
17 7 7
13 2 10
12 18 3
16 15 19
5 6 2
Sample Output
输出1:
18
输出2:
110
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
首先我们看一下X=0的10point怎么做(这其实提示了我们正解)
假设我们要取t2个2类点,t3个3类点
不妨先全部取2类点,然后把差值最大的t3个转化为3类点,这样显然是最优的
我们现在要拓展这个贪心
设每一个三元组为(x,y,z)那么我们可以先把它转化为(0,y-x,z-x)(设其为(0,y’,z’)),然后最后答案再加上(t1+t2+t3)*x
那么我们就十分惊喜的发现这样的三元组可以当做二元组做了
我们可以先把y-z从大到小排序,设最后一个取y’的位置为i(其实我的程序是i后面没有取y’),那么我们可以发现i前面是不可能取0的(不然我肯定会在前面取0的位置取y’),那么i的前面就只有y’和z’,后面只有z’和0
也就是说在确定了i之后我们就知道了i前面z’的个数以及i后面z’的个数(设为cc1,cc2)
那么我们可以找到i前面最大的cc1个z’-y’,后面最大的cc2个z’
发现范围比较小,所以可以用一个类似于桶排的方法达到线性的复杂度(带log会被卡常)
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
#define ll long long
#define cs 500001
using namespace std;
const int maxn=5e5+5;
struct P{
ll y,z;
}a[maxn];
int st1[maxn*2],st2[maxn*2];
ll f[maxn],g[maxn];
ll i,j,k,l,n,m,x,y,z,t1,t2,t3,t,ans,sh,now,tot;
char ch;
int read(){
int x=0;
ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
return x;
}
int cmp(P x,P y){
return x.y>y.y;
}
int main(){
freopen("triple.in","r",stdin);
freopen("triple.out","w",stdout);
t1=read(); t2=read(); t3=read();
t=t1+t2+t3;
fo(i,1,t){
x=read(); y=read(); z=read();
tot+=x; y-=x; z-=x;
a[i].y=y; a[i].z=z;
}
sort(a+1,a+t+1,cmp);
fo(i,1,t2){
st1[a[i].z-a[i].y+cs]++;
now=max(now,a[i].z-a[i].y+cs);
f[t2]+=a[i].y;
}
sh=st1[now];
fo(i,t2+1,t-t1){
f[i]=f[i-1]+a[i].y;
if (a[i].z-a[i].y+cs>=now) f[i]=f[i]+a[i].z-a[i].y; else{
st1[a[i].z-a[i].y+cs]++;
if (sh==0){
now--;
while (st1[now]==0) now--;
sh=st1[now];
}
sh--;
f[i]=f[i]+now-cs;
}
}
now=0;
fo(i,t-t1+1,t){
st2[a[i].z+cs]++;
now=max(now,a[i].z+cs);
}
sh=st2[now];
fo1(i,t-t1,t2+1){
if (a[i].z+cs>=now) g[i]=g[i+1]+a[i].z; else{
st2[a[i].z+cs]++;
if (sh==0){
now--;
while (st2[now]==0) now--;
sh=st2[now];
}
sh--;
g[i]=g[i+1]+now-cs;
}
}
fo(i,t2,t-t1) ans=max(ans,f[i]+g[i+1]);
ans+=tot;
printf("%lld",ans);
return 0;
}