传送门:BZOJ1562-变换序列
由于题目是图片形式,就不贴了。
题解
我们把每个数与可以变换的两个标号之间连一条无向边,跑一下二分图最大匹配就好啦。
注意dfs的顺序和边的排序
代码
#include<bits/stdc++.h>
#define o(x,y) g[x].push_back(y);
using namespace std;
const int N=1e4+10;
int n,x,now,lk[N<<1];
int vis[N<<1],cnt,ans;
vector<int>g[N<<1];
inline bool dfs(int x)
{
int oi,len=g[x].size();
for(int i=0;i<len;i++){
oi=g[x][i];
if(vis[oi]!=cnt){
vis[oi]=cnt;
if(lk[oi]==-1){
lk[oi]=x;
return true;
}else if(dfs(lk[oi])){
lk[oi]=x;
return true;
}
}
}
return false;
}
inline int maxmatch()
{
int num=0;
for(int i=n-1;i>=0;i--){
cnt++;
if(dfs(i)){
num++;
}
}
return num;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&x);
now=(i+x)%n + n;
g[i].push_back(now);
g[now].push_back(i);
now=(i-x+n)%n + n;
g[i].push_back(now);
g[now].push_back(i);
}
for(int i=0;i<(n<<1);i++){
sort(g[i].begin(),g[i].end());
lk[i]=-1;
}
ans=maxmatch();
if(ans!=n){
printf("No Answer\n");
}else{
for(int i=0;i<n;i++){
lk[lk[i+n]]=i;
}
for(int i=0;i<n;i++){
printf("%d",lk[i]);
if(i!=n-1){
printf(" ");
}
}
}
return 0;
}