bzoj 1562: [NOI2009]变换序列

题意:有一个长度为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]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值