我可能真的只会网络流……二分图的题一点都做不来……
首先每个位置有两种取值,所以建一个二分图,只要有完美匹配就说明有解
考虑一下每一个位置,分别让它选择两种取值,如果都不能形成完美匹配,说明无解
然后考虑要让字典序最小。考虑一下匈牙利的过程,我们每一次如果遇到右边的点有匹配,我们都会让它把那个匹配给挤掉
那么我们考虑倒着做,这样的话每一次都必定是字典序小的挤掉字典序大的,可以保证最优
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 const int N=10005; 19 int Pre[N],er[N],vis[N],path[N][2]; 20 int n; 21 bool dfs(int u,int tm){ 22 if(vis[u]==tm) return false; 23 vis[u]=tm; 24 for(int i=0;i<2;++i){ 25 int v=path[u][i]; 26 if(!Pre[v]||dfs(Pre[v],tm)){ 27 Pre[v]=u,er[u]=v; 28 return true; 29 } 30 } 31 return false; 32 } 33 int main(){ 34 n=read(); 35 for(int i=0;i<n;++i){ 36 int x=read(); 37 path[i][0]=min((x+i)%n,(n-x+i)%n); 38 path[i][1]=max((x+i)%n,(n-x+i)%n); 39 } 40 memset(vis,-1,sizeof(vis)); 41 for(int i=n-1;~i;--i){ 42 if(!dfs(i,i)) return puts("No Answer"),0; 43 } 44 for(int i=0;i<n;++i) printf("%d ",er[i]); 45 return 0; 46 }