题意
太长了不想写。
分析
考虑建图,源点往每个选手连流量为1的边,每个导师往汇点连流量为战队人数的边,其余边先不连。
现在按编号从小到大考虑每个选手,把代表该选手的志愿的边从小到大逐个加入,每加入一个志愿就判断是否存在增广路,若存在则退出即可。
时间复杂度O(n4)O(n4)
对于第二问,还是类似的做法。对于每一个选手,枚举一个排名,在第一问的残余网络上把该排名之后的选手全部删掉,然后把该选手的前s个志愿加入,判断一下是否有增广路即可。
注意每次判断完后都要撤销。
时间复杂度O(n4)O(n4)
什么你说这个复杂度理论上会被卡?那就把第一问的逐个加志愿变成二分志愿,把第二问的枚举排名变成二分排名,复杂度就变成了O(n3logn)O(n3logn)
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=405;
int n,m,cnt,last[N],ans[N],r[N],tcnt,tlast[N],s,t,pre[N],num[N];
bool vis[N];
struct edge{int to,next,c;}e[N*N*2],te[N*N*2];
queue<int> que;
vector<int> vec[N][N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void addedge(int u,int v,int c)
{
e[++cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt;
}
void build(int x,int y)
{
for (int i=1;i<=y;i++)
for (int j=0;j<vec[x][i].size();j++)
addedge(x,vec[x][i][j]+n,1);
}
bool flow()
{
for (int i=s;i<=t;i++) vis[i]=0;
while (!que.empty()) que.pop();
vis[s]=1;que.push(s);
while (!que.empty())
{
int u=que.front();que.pop();
for (int i=last[u];i;i=e[i].next)
if (e[i].c&&!vis[e[i].to])
{
pre[e[i].to]=i;
vis[e[i].to]=1;
que.push(e[i].to);
}
if (vis[t]) break;
}
if (!vis[t]) return 0;
int x=t;
while (x!=s)
{
e[pre[x]].c--;e[pre[x]^1].c++;
x=e[pre[x]^1].to;
}
return 1;
}
void res(int op)
{
if (!op)
{
tcnt=cnt;
for (int i=1;i<=cnt;i++) te[i]=e[i];
for (int i=s;i<=t;i++) tlast[i]=last[i];
}
else
{
cnt=tcnt;
for (int i=1;i<=tcnt;i++) e[i]=te[i];
for (int i=s;i<=t;i++) last[i]=tlast[i];
}
}
void del(int x)
{
e[num[x]].c=e[num[x]^1].c=0;
int y;
for (int i=last[x];i;i=e[i].next)
{
if (!e[i].c&&e[i].to) y=e[i].to;
e[i].c=e[i^1].c=0;
}
e[num[y]].c--;e[num[y]^1].c++;
}
bool check(int x,int y)
{
res(0);
build(x,y);
bool ans=flow();
res(1);
return ans;
}
bool check1(int x,int y)
{
res(0);
for (int i=x-y;i<=n;i++) if (ans[i]<=m) del(i);
e[num[x]^1].c=1;
build(x,r[x]);
bool w=flow();
res(1);
return w;
}
int main()
{
int T=read(),C=read();
while (T--)
{
n=read();m=read();
s=0;t=n+m+1;cnt=1;
for (int i=s;i<=t;i++) last[i]=0;
for (int i=1,x;i<=m;i++) x=read(),addedge(i+n,t,x),num[i+n]=cnt;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) vec[i][j].clear();
for (int j=1;j<=m;j++)
{
int x=read();
if (x) vec[i][x].push_back(j);
}
}
for (int i=1;i<=n;i++) r[i]=read(),addedge(s,i,1),num[i]=cnt;
for (int i=1;i<=n;i++)
{
int l=1,r=m;
while (l<=r)
{
int mid=(l+r)/2;
if (check(i,mid)) r=mid-1;
else l=mid+1;
}
printf("%d ",ans[i]=r+1);
if (r<m) build(i,r+1),flow();
}
puts("");
for (int i=1;i<=n;i++)
{
if (ans[i]<=r[i]) {printf("%d ",0);continue;}
int l=1,r=i-1;
while (l<=r)
{
int mid=(l+r)/2;
if (check1(i,mid)) r=mid-1;
else l=mid+1;
}
printf("%d ",r+1);
}
puts("");
}
return 0;
}