NC17619. [NOI2009]变换序列
描述
对于N个整数0, 1, ……,N-1,一个变换序列T可以将i变成Ti,其中且。,定义x和y之间的距离。给定每个i和Ti之间的距离D(i,Ti),你需要求出一个满足要求的变换序列T。如果有多个满足条件的序列,输出其中字典序最小的一个。
说明:对于两个变换序列S和T,如果存在p<N,满足对于i=0,1,……p-1,Si=Ti且Sp<Tp,我们称S比T字典序小。
输入描述
第一行包含一个整数N,表示序列的长度。接下来的一行包含N个整数Di,其中Di表示i和Ti之间的距离。
输出描述
如果至少存在一个满足要求的变换序列T,则输出文件中包含一行N个整数,表示你计算得到的字典序最小的T;否则输出”No Answer”(不含引号)。注意:输出文件中相邻两个数之间用一个空格分开,行末不包含多余空格。
示例1
输入:
5 1 1 2 2 1
输出:
1 2 4 0 3
C++14(g++5.4) 解法, 执行用时: 6ms, 内存消耗: 580K, 提交时间: 2020-08-02 11:06:14
#include<bits/stdc++.h> using namespace std; const int N=1e4+5,M=4e4+5; int Next[N][2]; int n; bool v[N];int match[N]; int ans[N]; bool dfs(int x){ for(int i=0;i<=1;i++){ int y=Next[x][i]; if(v[y]) continue; v[y]=1; if(match[y]==-1||dfs(match[y])){ match[y]=x; ans[x]=y; return 1; } }return 0; } int main(){ cin>>n; for(int i=0;i<n;i++){ int x;cin>>x; Next[i][0]=(i+x)%n; Next[i][1]=(i-x+n)%n; if(Next[i][0]>Next[i][1]) swap(Next[i][0],Next[i][1]); match[i]=-1; } for(int i=n-1;i>=0;i--){ memset(v,0,sizeof(v)); if(!dfs(i)){ cout<<"No Answer";return 0; } } for(int i=0;i<n;i++){ if(i!=n-1) cout<<ans[i]<<' '; else cout<<ans[i]; } }
C++11(clang++ 3.9) 解法, 执行用时: 29ms, 内存消耗: 748K, 提交时间: 2019-04-02 17:28:04
#include<bits/stdc++.h> using namespace std; const int N = 110000; int n,v; int d[N],s[N][2],vis[N],to[N],lykkk[N]; bool hungry(int u){ for(int i=0;i<=1;++i) if(!vis[s[u][i]]){ int v=s[u][i]; vis[v]=1; if(lykkk[v]==-1 || hungry(lykkk[v])){ lykkk[v]=u; to[u]=v; return 1; } } return 0; } int main(){ cin>>n; for(int i=0;i<=n-1;++i) cin>>d[i]; for(int i=0;i<=n-1;++i){ s[i][0]=(i+d[i]+n)%n; s[i][1]=(i-d[i]+n)%n; if(s[i][0]>s[i][1]) swap(s[i][0],s[i][1]); lykkk[i]=to[i]=-1; } for(int i=n-1;i>=0;--i){ for(int j=0;j<=n-1;++j) vis[j]=0; if(!hungry(i)){ cout<<"No Answer"; return 0; } } for(int i=0;i<=n-1;++i) cout<<to[i]<<" "; return 0; }