1 solutions
-
0
CF1861F 题解
题目大意
有 个人, 种不同的卡牌,初始第 个人有 张第 种卡牌。
你是局外人,手里第 种卡牌有 个,你现在要把你的卡牌分给这 个人,使得分完之后每个人手里的卡牌总数相等,保证有解。
第 个人最终的分数是手里每种卡牌的数量的最大值。分数最高的那个人如果分数为 ,除了他之外分数最高的人的分数为 ,那么他会获得 的喜悦程度(显然如果存在两个分数最高的,那么他们的喜悦度都是 ),其他人会获得 的喜悦程度。
对于每个人,算出他最大的可能的喜悦程度。
数据范围:。
思路分析
设 为最终每个人的总卡牌数, 表示第 个人距离拿满还差多少。
考虑分开处理,枚举第 个人手中得分来自哪种卡牌 ,显然这种牌一定尽可能取到最大值,即给 个。
剩下的就是最小化其余人的最大的得分,显然先二分一个最大值上界 ,可以考虑建立网络流模型处理:
- 源点 向 连一条边权为 的边(注意这里的 要去掉第 个人拿走的卡牌 ),用于控制每种卡牌的总量。
- 然后 向 连一条边权为 的边(不包括枚举到的这个人),用于控制最大的得分。
- 所有 向汇点 连一条边权为 的边,用于控制每个人最终的总卡牌数。
显然答案有解当且仅当所有 满流,注意不能判断 满流,因为这里面还会剩下一点给第 个人的其他 种的卡牌。
考虑最大流转最小割,显然期望最大流 能算出来,那么我们只要判断是否所有割的权值都 即可。
考虑枚举保留那些 的边,记为 ,那么首先有 的代价。
然后考虑每个人的贡献,显然若想使 不连通,要么切掉 ,要么切掉所有 ,那么其贡献就是 。
对于每个 ,显然可以通过差分预处理出每个 所对应的答案,然后就可以直接 check 了。
时间复杂度 ,其中 。
代码呈现
#include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN=5e4+5,MAXK=4e6+5; int a[MAXN][4],b[4],g[16][MAXN],up[MAXN],pc[16],mx[MAXN],cnt[16][MAXK]; ll sum[16][MAXK],totup; signed main() { int n,K=0,le0=0,le1=0; scanf("%d",&n); for(int i=1;i<16;++i) pc[i]=1+pc[i&(i-1)]; for(int i=1;i<=n;++i) { for(int j:{0,1,2,3}) scanf("%d",&a[i][j]),K+=a[i][j]; mx[i]=*max_element(a[i],a[i]+4); le1=max(le1,min(le0,mx[i])),le0=max(le0,mx[i]); } for(int i:{0,1,2,3}) scanf("%d",&b[i]),K+=b[i]; K/=n; for(int i=1;i<=n;++i) { for(int j:{0,1,2,3}) up[i]+=a[i][j]; up[i]=K-up[i],totup+=up[i]; for(int s=1;s<16;++s) { for(int j=0;j<4;++j) if(s&(1<<j)) g[s][i]+=a[i][j]; } } for(int s=1;s<16;++s) { for(int i=1;i<=n;++i) { int x=(up[i]+g[s][i])/pc[s]+1; //max k: k|s|-g[i][s]<=up[i] sum[s][0]-=g[s][i],++cnt[s][0]; sum[s][x]+=g[s][i],--cnt[s][x]; sum[s][x]+=up[i]; } for(int i=1;i<=K;++i) sum[s][i]+=sum[s][i-1],cnt[s][i]+=cnt[s][i-1]; } for(int i=1;i<=n;++i) { int ans=0,le=(le0==mx[i])?le1:le0; for(int j:{0,1,2,3}) { int cur=min(up[i],b[j]),l=le,r=K,res=K; b[j]-=cur; function<bool(int)> check=[&](int k) { for(int s=0;s<16;++s) { ll cut=sum[s][k]+1ll*cnt[s][k]*pc[s]*k; cut-=min(pc[s]*k-g[s][i],up[i]); for(int x:{0,1,2,3}) if(!(s&(1<<x))) cut+=b[x]; if(cut<totup-up[i]) return false; //mincut <= expected flow } return true; }; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) r=mid-1,res=mid; else l=mid+1; } ans=max(ans,a[i][j]+cur-res),b[j]+=cur; } printf("%d ",ans); } puts(""); return 0; }
- 1
Information
- ID
- 10042
- Time
- 6000ms
- Memory
- 1024MiB
- Difficulty
- (None)
- Tags
- # Submissions
- 0
- Accepted
- 0
- Uploaded By