给定一个
n
≤
1
e
4
n\leq1e4
n≤1e4的序列,然后给出定义
D
(
x
,
y
)
=
m
i
n
{
∣
x
−
y
∣
,
n
−
∣
x
−
y
∣
}
D(x,y)=min\{|x-y|,n-|x-y|\}
D(x,y)=min{∣x−y∣,n−∣x−y∣},现在给出了
D
(
i
,
T
(
i
)
)
D(i,T(i))
D(i,T(i)),要求出一个变换后最小的全排列。
直接对每个
i
i
i连上所有的连边,理论上最多两种,枚举四种并且判定就可以了。然后跑二分图匹配,如果最大匹配小于
n
n
n,说明这种情形无解。否则直接输出结果。
注意二分图匹配是后者暴力替换前者,所以想要字典序最大需要倒序遍历。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e4+7;
int d[N],tim=0;
int n;
int link[N],used[N],link2[N];
vector<int> G[N];
bool check(int x,int y,int d) {
return min(abs(x-y),n-abs(x-y))==d;
}
int dfs(int u) {
for(auto &v:G[u]) {
if(used[v]==tim) continue;
used[v]=tim;
if(link[v]==-1||dfs(link[v])) {
link[v]=u;
link2[u]=v;
return 1;
}
}
return 0;
}
int solve() {
int ans=0;
memset(link,-1,sizeof(link));
for(int i=n;i>=0;i--) {
tim++;
if(dfs(i)) ++ans;
}
return ans;
}
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&d[i]);
for(int i=0;i<n;i++) {
if(i>=d[i]&&check(i,i-d[i],d[i])) G[i].push_back(i-d[i]);
if(i+d[i]<n&&check(i,i+d[i],d[i])) G[i].push_back(i+d[i]);
if(i>=n-d[i]&&check(i,i-(n-d[i]),d[i])) G[i].push_back(i-(n-d[i]));
if(i+(n-d[i])<n&&check(i,i+(n-d[i]),d[i])) G[i].push_back(i+(n-d[i]));
}
for(int i=0;i<n;i++)
sort(G[i].begin(),G[i].end());
int ans=solve();
if(ans<n) puts("No Answer");
else {
for(int i=0;i<n;i++)
printf("%d%c",link2[i],i==n-1?'\n':' ');
}
return 0;
}