bzoj 1562: [NOI2009]变换序列

来源:互联网 发布:我知谁掌管明天基督教 编辑:程序博客网 时间:2024/06/05 03:23

题意:有一个长度为n 的全排列,每个数i都对应一个Ti,求满足D(i,Ti)=ai的字典序最小的T。D(x,y)=min(|x-y|,n-|x-y|)
题解:二分图匹配。字典序比较棘手。首先建边的时候就先加大的在加小的,找的时候就会从小到大访问了。然后就是匹配的时候倒序来找,我的感性认识就是这样可以防止大的把小的抢了,导致字典序变大。严格证明
还有一点,行末不能有空格。
代码:

#include<bits/stdc++.h>using namespace std;int n,num=0,fst[10010],chk[10010],mch[10010],now=0,ans[10010];struct edge{    int x,y,n;}e[20010];void ins(int x,int y){    e[++num]={x,y,fst[x]};    fst[x]=num;}bool fd(int x){    for(int i=fst[x];i;i=e[i].n)    {        int y=e[i].y;        if(chk[y]!=now)        {            chk[y]=now;            if((mch[y]==-1||fd(mch[y])))            {                mch[y]=x;                return 1;            }        }    }    return 0;}int main(){    scanf("%d",&n);    for(int i=0;i<n;i++)    {        int x;        scanf("%d",&x);        int y1=(i+x)%n,y2=(i-x+n)%n;        if(y1<y2)        swap(y1,y2);        ins(i,y1);        ins(i,y2);    }    memset(chk,0,sizeof(chk));    memset(mch,-1,sizeof(mch));    for(int i=n-1;i>=0;i--)    {        now++;        if(!fd(i))        {            puts("No Answer");            return 0;        }    }    for(int i=0;i<n;i++)    ans[mch[i]]=i;    printf("%d",ans[0]);    for(int i=1;i<n;i++)    printf(" %d",ans[i]);}
原创粉丝点击