题目描述
轻车熟路的 Zayid 顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则 是这样的: 总共 n 名参赛选手(编号从 1 至 n)每人写出一份代码并介绍自己的梦想。接着由 所有导师对这些选手进行排名。为了避免后续的麻烦,规定不存在排名并列的情况。 同时,每名选手都将独立地填写一份志愿表,来对总共 m 位导师(编号从 1 至 m) 作出评价。志愿表上包含了共 m 档志愿。对于每一档志愿,选手被允许填写最多 C 位 导师,每位导师 · 最 · 多被每位选手填写一次(放弃某些导师也是被允许的)。 在双方的工作都完成后,进行录取工作。每位导师都有自己战队的人数上限,这意 味着可能有部分选手的较高志愿、甚至是全部志愿无法得到满足。 节目组对 ‘‘前 i 名的录取结果最优’’ 作出如下定义:
• 前 1 名的录取结果最优,当且仅当第 1 名被其最高非空志愿录取(特别地,如 果第 1 名没有填写志愿表,那么该选手出局)。
• 前 i 名的录取结果最优,当且仅当在前 i−1 名的录取结果最优的情况下:第 i 名 被其理论可能的最高志愿录取(特别地,如果第 i 名没有填写志愿表、或其所有 志愿中的导师战队均已满员,那么该选手出局)。如果一种方案满足 ‘‘前 n 名的录取结果最优’’,那么我们可以简称这种方案是最优的。
唯一的最优录取结果。 每个人都有一个自己的理想值 si,表示第 i 位同学希望自己被第 si 或更高的志愿录 取,如果没有,那么他就会非常沮丧。 现在,所有选手的志愿表和排名都已公示。巧合的是,每位选手的排名都恰好与它 们的编号相同。 对于每一位选手,Zayid 都想知道下面两个问题的答案:
• 在最优的录取方案中,他会被第几志愿录取。
• 在其他选手相对排名不变的情况下,至少上升多少名才能使得他不沮丧。 作为《中国新代码》的实力派代码手,Zayid 当然轻松地解决了这个问题。不过他 还是想请你再算一遍,来检验自己计算的正确性。
题目大意
给出每个人在志愿表,然后安排其导师,
第一问输出最优方案,第二问输出要第i个要满足他的要求的排名。
题解
对于第一问,就像二分图匹配一样,用网络流,但与普通的最大流有区别。
这里还是有所不同,这里要按照字典序。
首先所有导师与超级汇连边,边权为战斗人数最大值。
在上一个人确定之后的残余网络,按照这个人的志愿顺序加入新的边,流量为1。
每加入一个志愿,就跑一次增广路,看一下是否存在增广路,
如果有,那么就说明这个人只能选择这个志愿等级的导师。
确定了这个人的志愿等级,就将这个人与他这个等级的全部导师连一条边权为1的有向边。
在他后面的人,可以更改他的导师,但是一定会保证他的导师在这个等级上面。
对于第二问,
可以发现如果某个人在排名t满足他的期望,那么在排名t之前都一定满足,这就满足二分性。
考虑二分这个最大的满足他期望的排名t,这样就变为了第一问。
当某个人的排名为t的时候,他最优能满足第几志愿。
如果从头重新开始构建网络,这样肯定会超时。
因为n很小,而且网络里面最多不会超过5000条边,
所以就可以将网络的历史版本保留下来。
每次询问一个排名t的时候,就直接调取已经保存下来的网络,再加入新的边,判断有无增广路。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 5003
#define M 203
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
struct node
{
int x,y;
}p[N];
int nxt[N],to[N],v[N],lst[N],cur[N],tot;
int q[N],h[N],S,T,ans;
int t,c,n,m,x,y,a[M][M],mm,te[N];
int _v[M][N],_lst[M][N],_to[M][N],_nxt[M][N],_tot[M];
int s[M],l,r,mid,sad;
bool cmp(node a,node b)
{
return a.x<b.x;
}
bool bfs()
{
int head=0,tail=1;
for(int i=0;i<=T;i++)h[i]=-1;
q[0]=S;h[S]=0;
while(head!=tail)
{
int now=q[head];head++;
for(int i=lst[now];i;i=nxt[i])
if(v[i] && h[to[i]]==-1)
{
h[to[i]]=h[now]+1;
q[tail++]=to[i];
}
}
return h[T]!=-1;
}
int dfs(int x,int f)
{
if(x==T)return f;
int w,used=0;
for(int i=cur[x];i;i=nxt[i])
if(h[to[i]]==h[x]+1)
{
w=f-used;
w=dfs(to[i],min(w,v[i]));
v[i]-=w;v[i^1]+=w;
if(v[i])cur[x]=i;
used+=w;
if(used==f)return f;
}
if(!used)h[x]=-1;
return used;
}
void dinic()
{
while(bfs())
{
for(int i=0;i<=T;i++)
cur[i]=lst[i];
ans+=dfs(S,inf);
}
}
void ins(int x,int y,int z)
{
nxt[++tot]=lst[x];
to[tot]=y;
v[tot]=z;
lst[x]=tot;
}
void _ins(int id,int x,int y,int z)
{
_nxt[id][++_tot[id]]=_lst[id][x];
_to[id][_tot[id]]=y;
_v[id][_tot[id]]=z;
_lst[id][x]=_tot[id];
}
void work(int now,int pre)
{
mm=0;
for(int j=1;j<=m;j++)
if(a[now][j])p[++mm].x=a[now][j],p[mm].y=j;
sort(p+1,p+1+mm,cmp);
for(int j=1;j<=mm;j=x)
{
for(x=j+1;p[x].x==p[j].x && x<=mm;x++);
tot=_tot[pre];
for(int i=1;i<=tot;i++)to[i]=_to[pre][i],nxt[i]=_nxt[pre][i],v[i]=_v[pre][i];
for(int i=1;i<=T;i++)lst[i]=_lst[pre][i];
ins(S,now,1);ins(now,S,0);
for(int k=j;k<x;k++)
ins(now,p[k].y+n,1),ins(p[k].y+n,now,0);
ans=0;dinic();
if(ans)
{
te[now]=p[j].x;
return;
}
}
}
int main()
{
freopen("mentor.in","r",stdin);
freopen("mentor.out","w",stdout);
for(read(t),read(c);t;t--)
{
read(n),read(m),tot=1;
memset(lst,0,sizeof(lst));
S=n+m+1,T=S+1;
for(int i=1;i<=m;i++)
read(x),ins(i+n,T,x),ins(T,i+n,0);
memcpy(_lst[0],lst,sizeof(_lst[0]));
memcpy(_nxt[0],nxt,sizeof(_nxt[0]));
memcpy(_to[0],to,sizeof(_to[0]));
memcpy(_v[0],v,sizeof(_v[0]));
_tot[0]=tot;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
read(a[i][j]);
for(int i=1;i<=n;i++)
read(s[i]),te[i]=m+1;
for(int i=1;i<=n;i++)
{
work(i,i-1);
if(te[i]==m+1)
{
_tot[i]=_tot[i-1];
for(int k=1;k<=_tot[i];k++)
_nxt[i][k]=_nxt[i-1][k],_to[i][k]=_to[i-1][k],_v[i][k]=_v[i-1][k];
for(int k=1;k<=T;k++)_lst[i][k]=_lst[i-1][k];
}
else
{
_tot[i]=tot;
for(int k=1;k<=tot;k++)
_nxt[i][k]=nxt[k],_to[i][k]=to[k],_v[i][k]=v[k];
for(int k=1;k<=T;k++)_lst[i][k]=lst[k];
}
}
for(int i=1;i<=n;i++)
write(te[i]),P(' ');P('\n');
for(int i=1;i<=n;i++)
{
l=1;r=i;sad=0;
while(l<r)
{
mid=(l+r)>>1;te[i]=m+1;work(i,mid-1);
if(te[i]<=s[i])sad=mid,l=mid+1;else r=mid;
}
te[i]=m+1;work(i,l-1);
if(te[i]<=s[i])sad=l;
write(i-sad);P(' ');
}
P('\n');
}
}