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问选出的数的和最大是多少
问选出的数的和最大是多少
Solution1
考虑可撤销贪心,
显然,这题你可以通过交换两个决策,使答案越来越优,直到最优,
当然,有可能不止是交换两个决策,而是交换三个决策(都是个环)
这个用线段树或堆维护即可,复杂度O(nlog(n))
发现数据=给出的范围比较小,可以用像桶一样的方式维护即可,
复杂度:O(n)
Solution2
假设n3=0,
先全部选第一个,
那么第二个怎么选呢?肯定是选减掉第一个加上第二个最大的那前n2个,
那试着推广一下,
先全部选第一个,
枚举n2选i个(i>=n2),
在选的i个中选(-第二个加第三个)的值前(i-n2)大的,他们就选第三个了,
剩下的第三个就从第一个中选,
这个用对维护就是O(nlog(n))的,
但我们发现,数的范围比较小,用像桶一样的方式维护即可,
复杂度:O(n)
Code
#pragma GCC optimize(2)
#include <cstdio>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
#define JS(q,i,j) ((q)?a[q][j]-a[q][i]:-1e9)
#define MX(i,j,q,w) ((JS(q,i,j)>JS(w,i,j))?q:w)
using namespace std;
typedef long long LL;
const int N=500500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,n1,n2,n3;
LL ans;
int a[N][3];
int b1[3][N],bv[N];
int b[N*4][3][3];
void build(int l,int r,int e)
{
if(l==r)
{
b[e][bv[l]][0]=l;
b[e][bv[l]][1]=l;
b[e][bv[l]][2]=l;
return;
}
int t=(l+r)>>1;
build(l,t,e*2);
build(t+1,r,e*2+1);
fo(i,0,2)fo(j,0,2)b[e][i][j]=MX(i,j,b[e*2][i][j],b[e*2+1][i][j]);
}
void change(int l,int r,int e,int l1,int l2,int l3)
{
if(l==r)
{
b[e][bv[l]][0]=0;
b[e][bv[l]][1]=0;
b[e][bv[l]][2]=0;
bv[l]=l2;
b[e][l2][0]=l;
b[e][l2][1]=l;
b[e][l2][2]=l;
return;
}
int t=(l+r)>>1;
if(l1<=t)change(l,t,e*2,l1,l2,l3);
else change(t+1,r,e*2+1,l1,l2,l3);
fo(i,0,2)
{
b[e][l2][i]=MX(l2,i,b[e*2][l2][i],b[e*2+1][l2][i]);
b[e][l3][i]=MX(l3,i,b[e*2][l3][i],b[e*2+1][l3][i]);
}
}
int main()
{
freopen("triple.in","r",stdin);
freopen("triple.out","w",stdout);
int q,w,e;
read(n1),read(n2),read(n3);
n=n1+n2+n3;
fo(i,1,n)fo(j,0,2)read(a[i][j]);
q=1;
fo(i,1,n1)ans+=(LL)a[i][0],b1[0][++q]=i,bv[i]=0;
q=0;
fo(i,n1+1,n1+n2)ans+=(LL)a[i][1],b1[1][++q]=i,bv[i]=1;
q=0;
fo(i,n1+n2+1,n)ans+=(LL)a[i][2],b1[2][++q]=i,bv[i]=2;
build(1,n,1);
while(1)
{
int t=-1e9;e=0;
fo(i,0,2)fo(j,i+1,2)
{
int t1=JS(b[1][i][j],i,j)+JS(b[1][j][i],j,i);
if(t1>t)t=t1,q=i,w=j;
}
int t1=JS(b[1][0][1],0,1)+JS(b[1][1][2],1,2)+JS(b[1][2][0],2,0);
if(t1>t)t=t1,q=1,w=2,e=3;
t1=JS(b[1][0][2],0,2)+JS(b[1][2][1],2,1)+JS(b[1][1][0],1,0);
if(t1>t)t=t1,q=1,w=3,e=2;
t1=JS(b[1][1][0],1,0)+JS(b[1][0][2],0,2)+JS(b[1][2][1],2,1);
if(t1>t)t=t1,q=2,w=1,e=3;
t1=JS(b[1][1][2],1,2)+JS(b[1][2][0],2,0)+JS(b[1][0][1],0,1);
if(t1>t)t=t1,q=2,w=3,e=1;
t1=JS(b[1][2][0],2,0)+JS(b[1][0][1],0,1)+JS(b[1][1][2],1,2);
if(t1>t)t=t1,q=3,w=1,e=2;
t1=JS(b[1][2][1],2,1)+JS(b[1][1][0],1,0)+JS(b[1][0][2],0,2);
if(t1>t)t=t1,q=3,w=2,e=1;
if(t>0)
{
ans+=(LL)t;
if(!e)
{
change(1,n,1,b[1][q][w],w,q);
change(1,n,1,b[1][w][q],q,w);
}else
{
q--,w--,e--;
change(1,n,1,b[1][q][w],w,q);
change(1,n,1,b[1][w][e],e,w);
change(1,n,1,b[1][e][q],q,e);
}
}else break;
}
printf("%lld\n",ans);
return 0;
}