bzoj 5251: [2018多省省队联测]劈配
2018-04-21 17:06
357 查看
Description
一年一度的综艺节目《中国新代码》又开始了。
Zayid从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了。
题目描述
轻车熟路的Zayid顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的:
总共n名参赛选手(编号从1至n)每人写出一份代码并介绍自己的梦想。接着由所有导师对这些选手进行排名。
为了避免后续的麻烦,规定不存在排名并列的情况。
同时,每名选手都将独立地填写一份志愿表,来对总共m位导师(编号从1至m)作出评价。
志愿表上包含了共m档志愿。
对于每一档志愿,选手被允许填写最多C位导师,每位导师最多被每位选手填写一次(放弃某些导师也是被允许的)。
在双方的工作都完成后,进行录取工作。
每位导师都有自己战队的人数上限,这意味着可能有部分选手的较高志愿、甚至是全部志愿无法得到满足。节目组对”
前i名的录取结果最优“作出如下定义:
前1名的录取结果最优,当且仅当第1名被其最高非空志愿录取(特别地,如果第1名没有填写志愿表,那么该选手出局)。
前i名的录取结果最优,当且仅当在前i-1名的录取结果最优的情况下:第i名被其理论可能的最高志愿录取
(特别地,如果第i名没有填写志愿表、或其所有志愿中的导师战队均已满员,那么该选手出局)。
如果一种方案满足‘‘前n名的录取结果最优’’,那么我们可以简称这种方案是最优的。
举例而言,2位导师T老师、F老师的战队人数上限分别都是1人;2位选手Zayid、DuckD分列第1、2名。
那么下面3种志愿表及其对应的最优录取结果如表中所示:
可以证明,对于上面的志愿表,对应的方案都是唯一的最优录取结果。
每个人都有一个自己的理想值si,表示第i位同学希望自己被第si或更高的志愿录取,如果没有,那么他就会非常沮丧。
现在,所有选手的志愿表和排名都已公示。巧合的是,每位选手的排名都恰好与它们的编号相同。
对于每一位选手,Zayid都想知道下面两个问题的答案:
在最优的录取方案中,他会被第几志愿录取。
在其他选手相对排名不变的情况下,至少上升多少名才能使得他不沮丧。
作为《中国新代码》的实力派代码手,Zayid当然轻松地解决了这个问题。
不过他还是想请你再算一遍,来检验自己计算的正确性。
然后对于第二问,显然可以二分答案
但是每一次暴力建图是不行的,实际上我们可以把图存下来,这样每一次 \(check\) 就是找一条增广路的时间了,所以复杂度瓶颈反而在第一问了
复杂度 \(O(n*m*flow)\)
一年一度的综艺节目《中国新代码》又开始了。
Zayid从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了。
题目描述
轻车熟路的Zayid顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的:
总共n名参赛选手(编号从1至n)每人写出一份代码并介绍自己的梦想。接着由所有导师对这些选手进行排名。
为了避免后续的麻烦,规定不存在排名并列的情况。
同时,每名选手都将独立地填写一份志愿表,来对总共m位导师(编号从1至m)作出评价。
志愿表上包含了共m档志愿。
对于每一档志愿,选手被允许填写最多C位导师,每位导师最多被每位选手填写一次(放弃某些导师也是被允许的)。
在双方的工作都完成后,进行录取工作。
每位导师都有自己战队的人数上限,这意味着可能有部分选手的较高志愿、甚至是全部志愿无法得到满足。节目组对”
前i名的录取结果最优“作出如下定义:
前1名的录取结果最优,当且仅当第1名被其最高非空志愿录取(特别地,如果第1名没有填写志愿表,那么该选手出局)。
前i名的录取结果最优,当且仅当在前i-1名的录取结果最优的情况下:第i名被其理论可能的最高志愿录取
(特别地,如果第i名没有填写志愿表、或其所有志愿中的导师战队均已满员,那么该选手出局)。
如果一种方案满足‘‘前n名的录取结果最优’’,那么我们可以简称这种方案是最优的。
举例而言,2位导师T老师、F老师的战队人数上限分别都是1人;2位选手Zayid、DuckD分列第1、2名。
那么下面3种志愿表及其对应的最优录取结果如表中所示:
可以证明,对于上面的志愿表,对应的方案都是唯一的最优录取结果。
每个人都有一个自己的理想值si,表示第i位同学希望自己被第si或更高的志愿录取,如果没有,那么他就会非常沮丧。
现在,所有选手的志愿表和排名都已公示。巧合的是,每位选手的排名都恰好与它们的编号相同。
对于每一位选手,Zayid都想知道下面两个问题的答案:
在最优的录取方案中,他会被第几志愿录取。
在其他选手相对排名不变的情况下,至少上升多少名才能使得他不沮丧。
作为《中国新代码》的实力派代码手,Zayid当然轻松地解决了这个问题。
不过他还是想请你再算一遍,来检验自己计算的正确性。
Solution
直接暴力网络流判断一个人能否选到这个志愿,不能选到我们就把新加的边去掉就可以了然后对于第二问,显然可以二分答案
但是每一次暴力建图是不行的,实际上我们可以把图存下来,这样每一次 \(check\) 就是找一条增广路的时间了,所以复杂度瓶颈反而在第一问了
复杂度 \(O(n*m*flow)\)
#include<bits/stdc++.h> using namespace std; const int N=510,M=N*N,inf=1e8; int n,m,b ,a ,C,head ,nxt[M],num=1,to[M],dis[M],S=0,T; inline void link(int x,int y,int z){ nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z; nxt[++num]=head[y];to[num]=x;head[y]=num;dis[num]=0; } int f ,dep ,s ; vector<int>v ;queue<int>Q; inline bool bfs(){ for(int i=S;i<=T;i++)dep[i]=0; Q.push(S);dep[S]=1; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=head[x];i;i=nxt[i]){ int u=to[i]; if(dis[i]<=0 || dep[u])continue; dep[u]=dep[x]+1;Q.push(u); } } return dep[T]; } inline int dfs(int x,int flow){ if(x==T || !flow)return flow; int tot=0,u,t; for(int i=head[x];i;i=nxt[i]){ u=to[i]; if(dis[i]<=0 || dep[u]!=dep[x]+1)continue; t=dfs(u,min(flow,dis[i])); dis[i]-=t;dis[i^1]+=t; flow-=t;tot+=t; if(!flow)break; } if(!tot)dep[x]=-1; return tot; } inline int Dinic(){ int ret=0,t=0; while(bfs()){ t=dfs(S,inf); while(t)ret+=t,t=dfs(S,inf); } return ret; } int st ,reb ,top=0; inline bool ok(int x,int y){ if(v[x][y].empty())return false; int last=num;top=0; st[++top]=x;reb[top]=head[x]; for(int i=v[x][y].size()-1;i>=0;i--){ int k=v[x][y][i]; st[++top]=n+k;reb[top]=head[n+k]; link(x,n+k,1); } if(Dinic())return true; num=last; while(top)head[st[top]]=reb[top],top--; return false; } inline void cmp(){for(int i=S;i<=T;i++)head[i]=0;num=1;} inline void Clear(){ cmp(); for(int i=1;i<=n;i++){ f[i]=0; for(int j=1;j<=m;j++)vector<int>().swap(v[i][j]); } } struct data{ int head ,to[5010],nxt[5010],dis[5010],num; }e ; inline bool check(int x,int y){ num=e[y-1].num; for(int i=S;i<=T;i++)head[i]=e[y-1].head[i]; for(int i=2;i<=num;i++) nxt[i]=e[y-1].nxt[i],to[i]=e[y-1].to[i],dis[i]=e[y-1].dis[i]; link(S,x,1);int t=N; for(int j=1;j<=m;j++)if(ok(x,j)){t=j;break;} return t<=s[x]; } inline void work(){ memset(e,0,sizeof(e)); scanf("%d%d",&n,&m);T=n+m+1; for(int i=1;i<=m;i++)scanf("%d",&b[i]),link(i+n,T,b[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); if(a[i][j])v[i][a[i][j]].push_back(j); } e[0].num=num; for(int k=2;k<=num;k++) e[0].nxt[k]=nxt[k],e[0].to[k]=to[k],e[0].dis[k]=dis[k]; for(int k=S;k<=T;k++)e[0].head[k]=head[k]; for(int i=1;i<=n;i++)scanf("%d",&s[i]); for(int i=1;i<=n;i++){ link(S,i,1); for(int j=1;j<=m;j++) if(ok(i,j)){f[i]=j;break;} e[i].num=num; for(int k=2;k<=num;k++) e[i].nxt[k]=nxt[k],e[i].to[k]=to[k],e[i].dis[k]=dis[k]; for(int k=S;k<=T;k++)e[i].head[k]=head[k]; } for(int i=1;i<=n;i++)if(!f[i])f[i]=m+1; for(int i=1;i<=n;i++)printf("%d ",f[i]);puts(""); for(int i=1;i<=n;i++){ if(f[i]<=s[i]){printf("0 ");continue;} int ret=i,l=1,r=i-1,mid; while(l<=r){ mid=(l+r)>>1; if(check(i,mid))ret=i-mid,l=mid+1; else r=mid-1; } printf("%d ",ret); } Clear();puts(""); } int main(){ freopen("mentor.in","r",stdin); freopen("mentor.out","w",stdout); int Ti;cin>>Ti>>C; while(Ti--)work(); return 0; }
相关文章推荐
- bzoj5251: [2018多省省队联测]劈配
- bzoj 5252: [2018多省省队联测]林克卡特树
- BZOJ5249: [2018多省省队联测]IIIDX
- bzoj 5248: [2018多省省队联测]一双木棋
- [BZOJ5251][九省联考2018]劈配(网络流)
- 【BZOJ5251】【八省联考2018】劈配(网络流,二分答案)
- BZOJ_5249_Luogu_P4364_[2018多省省队联测]_IIIDX_九省联考2018_JLOI2018_线段树
- [BZOJ5251][多省联测2018]劈配
- |BZOJ 1036|树链剖分|线段树|[ZJOI2008]树的统计Count
- bzoj3218 a + b Problem
- BZOJ 4818: [Sdoi2017]序列计数 (动态规划+矩阵乘法)
- bzoj1375 [Baltic2002]Bicriterial routing 双调路径 (两个值的最短路)
- BZOJ 1016 星球大战starwar(逆向-并查集)
- BZOJ 1706 usaco2007 Nov relays 奶牛接力跑 倍增Floyd
- bzoj 1497 [NOI2006]最大获利
- [BZOJ]4644: 经典傻逼题
- bzoj 3996 最小割
- 【splay】BZOJ 1251 序列终结者
- [bzoj4520][Cqoi2016]K远点对
- BZOJ 3293/1465/1045([Cqoi2011]分金币/糖果传递/[HAOI2008] 糖果传递-列方程)