「九省联考 2018」劈配
写了一个有点奇怪的做法(感觉
首先发现有个比较正常的暴力,就是每次二分重新建图跑,似乎有80分,应该也比较好写,考场应该会写这个。
考虑如果得到了前\(i\)个人的答案(问题1),那么这些人只能在一部分的导师里面反悔,我们把这些边建出来。
然后对于\(i+1\sim n\)个人,每次把它所有边加上,然后看看它在这个排名可不可以达到它的期望,然后再把边撤回。
这里用一个单路增广就好,比较好撤回,可以发现这个单路增广是\(O(n+m)\)的
然后每个人跑了\(n\)次单路增广,\(m\)在建一部分边后大小应该是\(nc\)条的,所以总复杂度是\(O(Tn^3C)\),跑不满就可以过
Code:
#include
#include
#include
#include
const int N=420;
const int M=4e5;
const int inf=0x3f3f3f3f;
template
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int head[N],thead[N],edge[M],to[M],Next[M],cnt;
void add(int u,int v,int w)
{
to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
to[++cnt]=u,edge[cnt]=0,Next[cnt]=head[v],head[v]=cnt;
}
int n,m,s,t,bee[N][N],ans0[N],ans1[N],yuy[N];
int pre[N],vis[N],ti,Id,flag;
void dfs(int now)
{
vis[now]=ti;
if(now==t)
{
while(pre[now])
{
if((now>n&&now<=n+m)||now==t+1) Id=now;
now=to[pre[now]^1];
}
flag=0;
return;
}
for(int v,i=head[now];flag&&i;i=Next[i])
if(edge[i])
{
if(vis[v=to[i]]==ti) continue;
pre[v]=i;
dfs(v);
}
}
struct koito_yuu
{
int v,x;//第几志愿,节点标号
koito_yuu(){}
koito_yuu(int V,int X){v=V,x=X;}
bool friend operator <(koito_yuu a,koito_yuu b){return a.v>b.v;}
}yuu[N][N];
void work()
{
read(n),read(m);
s=n+m+1,t=s+1;
for(int b,i=1;i<=m;i++) read(b),add(i+n,t,b);
add(t+1,t,inf);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)//第i个人对第j个导师为第几志愿
read(bee[i][j]),yuu[i][j]=koito_yuu(bee[i][j],j+n);
bee[i][m+1]=m+1,yuu[i][m+1]=koito_yuu(m+1,t+1);
std::sort(yuu[i]+1,yuu[i]+1+m+1);
/*a[j]=mp(bee[i][j],j);
std::sort(a+1,a+1+m);
a[m+1]=mp(m+1,t+1);
bee[i][m+1]=m+1;
for(int j=m;~j;j--)
if(a[j].fisrt!=a[j+1].fisrt)
{
endro[i][a[j+1].fisrt]=head[i];//第i个人第j个志愿的
if(a[j].fisrt) add(i,a[j].second,1);
}
*/
}
for(int i=1;i<=n;i++) read(yuy[i]);
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
int tmp=cnt;
for(int k=1;k<=t+1;k++) thead[k]=head[k];
add(s,j,1);
for(int k=1;k<=m+1;k++)
{
if(!yuu[j][k].v) break;
add(j,yuu[j][k].x,1);
}
flag=1,++ti;
dfs(s);
Id=bee[j][Id==t+1?m+1:Id-n];
if(j==i) ans0[i]=Id;
if(Id<=yuy[j]) ans1[j]=i;
cnt=tmp;
for(int k=1;k<=t+1;k++) head[k]=thead[k];
}
add(s,i,1);
for(int j=1;j<=m+1;j++)
if(ans0[i]==yuu[i][j].v)
add(i,yuu[i][j].x,1);
flag=1,++ti;
dfs(s);
int now=t;
while(pre[now])
{
--edge[pre[now]];
++edge[pre[now]^1];
now=to[pre[now]^1];
}
}
for(int i=1;i<=n;i++) printf("%d ",ans0[i]);
puts("");
for(int i=1;i<=n;i++) printf("%d ",i-ans1[i]);
puts("");
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
int T,C;
read(T),read(C);
while(T--)
{
//待会清空放在这里,要检查
memset(head,0,sizeof head);
memset(pre,0,sizeof pre);
memset(ans1,0,sizeof ans1);
cnt=1;
work();
}
return 0;
}
2019.3.19