Description

Input

Output

Sample Input
5
1 1 2 2 1
1 1 2 2 1
Sample Output
1 2 4 0 3
HINT
30%的数据中N≤50;
60%的数据中N≤500;
100%的数据中N≤10000。
题解Here!
题面不是很好懂。。。
简化一下:每个数$i$能与$(i+d_i)\%N,(i-d_i+N)\%N$匹配,问每个数匹配后某位置匹配的原来的数是什么。
很明显建完边然后二分图匹配。。。
二分图匹配丢给了匈牙利。。。
但是那个字典序最小怎么整?
我们可以将每个数的匹配中,小的放前面,大的放后面,然后倒着做一遍匈牙利。
这时我们发现现有的匹配覆盖了原有的匹配。
并且字典序更小!
所以这么做是对的。
复杂度是非常松的$O(n^2)$。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 10010
using namespace std;
int n,T,c=1;
int head[MAXN],val[MAXN],f[MAXN],g[MAXN],vis[MAXN],map[MAXN][2];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
bool find(int x){
for(int k=0;k<=1;k++){
if(vis[map[x][k]]==T)continue;
int v=map[x][k];
vis[v]=T;
if(f[v]==-1||find(f[v])){
f[v]=x;g[x]=v;
return true;
}
}
return false;
}
void work(){
T=1;
for(int i=n-1;i>=0;i--){
if(!find(i)){
printf("No Answer");
return;
}
T++;
}
for(int i=0;i<n-1;i++)printf("%d ",g[i]);
printf("%d",g[n-1]);
}
void init(){
int u,v,w;
n=read();
memset(f,-1,sizeof(f));
for(int i=0;i<n;i++){
w=read();
u=(i-w+n)%n;v=(i+w)%n;
if(u>v)swap(u,v);
map[i][0]=u;map[i][1]=v;
}
}
int main(){
init();
work();
return 0;
}