题意:有一个长度为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]);
}