可以发现,每个数最多可以变成两个数,我们以此为边建二分图。然后跑完美匹配即可。题目还要求输出字典序最小的答案,这个怎么做呢?考虑我们匈牙利算法的过程,如果强制要求每个点先连向小的,再连向大的,则我们会尝试着先给当前数匹配小的,而之前匹配过的数要为他腾位置,因此我们只要倒着匹配就好啦!让最后匹配的尽量小。
严谨的证明见dalao byvoid:https://www.byvoid.com/zhs/blog/noi-2009-transform
%%%
#include <bits/stdc++.h>
using namespace std;
#define N 10010
#define ll long long
#define inf 0x3f3f3f3f
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,bf[N],gf[N];
bool f[N];
vector<int>e[N];
bool find(int x){
for(int i=0;i<e[x].size();++i){
int y=e[x][i];if(f[y]) continue;f[y]=1;
if(!bf[y]||find(bf[y])){
bf[y]=x;gf[x]=y;return 1;
}
}return 0;
}
int main(){
// freopen("a.in","r",stdin);
n=read();
for(int i=1;i<=n;++i){
int x=read(),x1,x2;
if(i-x>=1) x1=i-x;else x1=i-x+n;
if(x*2==n){e[i].push_back(x1);continue;}
if(i+x<=n) x2=i+x;else x2=i+x-n;
if(x1>x2) swap(x1,x2);e[i].push_back(x1);e[i].push_back(x2);
}
for(int i=n;i>=1;--i){
memset(f,0,sizeof(f));if(!find(i)){puts("No Answer");return 0;}
}
for(int i=1;i<n;++i) printf("%d ",gf[i]-1);printf("%d\n",gf[n]-1);
return 0;
}