AGC-018-C Coins——题解
AGC-018-C Coins——题解
思路
考虑一个贪心的思想,哪个人的某种币多,就对应地取那个人的某种币。但是可能某个人有多种币都很多的情况,那样就很难讨论取舍,这种时候就需要用上反悔了。
第一步,我们先随便选择 $ x $ 个人选金币, $ y $ 个人选银币, $ z $ 个人选铜币,由于我们可以反悔,所以初始的选择状态并不会产生影响。
第二步,我们需要考虑该如何反悔,很容易可以想到改变部分人的选择状态,同时由于固定有 $ x $ 个人选金币, $ y $ 个人选银币, $ z $ 个人选铜币,所以改变状态的某些人必然是形成一个环状的传递链。仔细思考后会发现只有以下五种情况:
- $ x->y,y->z,z->x $ ;
- $ x->z,y->x,z->y $ ;
- $ x->y,y->x $ ;
- $ y->z,z->y $ ;
- $ x->z,z->x $ 。
最后用用优先队列维护一下 $ 6 $ 种一对一的改变状态即可。
code
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=5e5+23,M=5e5+520,mod=536870912;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int X,Y,Z;
struct node
{
int w,id;
friend bool operator <(node x,node y){return x.w<y.w;}
};
priority_queue<node>q1,q2,q3,q4,q5,q6;
int a[N],b[N],c[N],vis[N];
fuck void add(int i)
{
q1.push((node){(b[i]-a[i]),i});//x->y
q2.push((node){(c[i]-b[i]),i});//y->z
q3.push((node){(c[i]-a[i]),i});//x->z
q4.push((node){(a[i]-b[i]),i});//y->x
q5.push((node){(b[i]-c[i]),i});//z->y
q6.push((node){(a[i]-c[i]),i});//z->x
}
int ans=0;
fuck void solve()
{
cin>>X>>Y>>Z;int n=X+Y+Z;memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i];
for(int i=1;i<=X;i++)vis[i]=1,ans+=a[i];
for(int i=X+1;i<=X+Y;i++)vis[i]=2,ans+=b[i];
for(int i=X+Y+1;i<=X+Y+Z;i++)vis[i]=3,ans+=c[i];
for(int i=1;i<=n;i++)add(i);
while(1)
{
while(!q1.empty()&&vis[q1.top().id]!=1)q1.pop();
while(!q2.empty()&&vis[q2.top().id]!=2)q2.pop();
while(!q3.empty()&&vis[q3.top().id]!=1)q3.pop();
while(!q4.empty()&&vis[q4.top().id]!=2)q4.pop();
while(!q5.empty()&&vis[q5.top().id]!=3)q5.pop();
while(!q6.empty()&&vis[q6.top().id]!=3)q6.pop();
//这里由于标记不符合队列要求的数据会被直接踢掉,所以后面暴力地往六个队列丢即可
int w1=(q1.empty()?-inf:q1.top().w);
int w2=(q2.empty()?-inf:q2.top().w);
int w3=(q3.empty()?-inf:q3.top().w);
int w4=(q4.empty()?-inf:q4.top().w);
int w5=(q5.empty()?-inf:q5.top().w);
int w6=(q6.empty()?-inf:q6.top().w);
int f=0,sum=0;
if(w1+w2+w6>sum)sum=w1+w2+w6,f=1;//x->y,y->z,z->x
if(w3+w4+w5>sum)sum=w3+w4+w5,f=2;//x->z,y->x,z->y
if(w1+w4>sum)sum=w1+w4,f=3;//x->y,y->x
if(w2+w5>sum)sum=w2+w5,f=4;//y->z,z->y
if(w3+w6>sum)sum=w3+w6,f=5;//x->z,z->x
if(sum==0){break;}
ans+=sum;
if(f==1)
{
int x=q1.top().id,y=q2.top().id,z=q6.top().id;
vis[x]=2,vis[y]=3,vis[z]=1;
add(x);add(y);add(z);
}
if(f==2)
{
int x=q3.top().id,y=q4.top().id,z=q5.top().id;
vis[x]=3,vis[y]=1,vis[z]=2;
add(x);add(y);add(z);
}
if(f==3)
{
int x=q1.top().id,y=q4.top().id;
vis[x]=2,vis[y]=1;
add(x),add(y);
}
if(f==4)
{
int y=q2.top().id,z=q5.top().id;
vis[y]=3,vis[z]=2;
add(y),add(z);
}
if(f==5)
{
int x=q3.top().id,z=q6.top().id;
vis[x]=3,vis[z]=1;
add(x),add(z);
}
}
cout<<ans<<"\n";
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
完结收工!!!!!

看完点赞,养成习惯
\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)

浙公网安备 33010602011771号