JZOJ5640. 【NOI2018模拟4.9】劈配

题目描述

轻车熟路的 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');
    }

}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/79877515