【NOI模拟赛(湖南)】DeepDarkFantasy
DeepDarkFantasy
从东京出发,不久便到一处驿站,写道:日暮里。 ——鲁迅《藤野先生》
定义一个置换的平方为对1~n的序列做两次该置换得到的序列。已知一个置换的平方,并且这个结果是一个排列,求该置换。
输入第一行一个数n表示排列长度,接下来一行n个数描述排列。
有解则输出一行n个数表示原排列。否则输出一行一个-1。
测试点编号 |
特征 |
0~1 |
n<=10 |
2~9 |
n<=1000000 |
【题解】
注:由于置换和排列在数学表现形式上是一样的,于是下文不对此进行详细区分。
首先对于任意一个排列,我们都可以将其看作一个有向图,即若排列中第i个点为x,那么相应的图中就会有一条从i连向x的边。那么对于一个置换的平方所得到的置换,相当于如果原图中有一条从x到y的边和一条从y到z的边,那么在新图中就会有一条从x到z的边。通过观察发现,原图中只有环的奇偶性会对答案的构成方式产生影响,于是我们可以对奇环和偶环分别进行讨论得到答案。
对于奇环的情况,可以令一个有5个点奇环为12345,那么在图中移动两步得到的图会是13524,那么如果中间有一个奇环的话,我们就可以按顺序遍历环的前一半和后一半得到原来的环。
对于偶环的情况,假设有一个偶环为123456,那么最终的结果会是形成两个环135与246,那么我们每次可以每次去两个环的同一位置上的数接在一起得到原来的环。
由于奇环所得到的答案一定是一个奇环,偶环得到的答案一定是两个长度相等的环,那么无解的情况就显然是新图中偶环的个数为奇数个。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 #include<algorithm> 8 #include<vector> 9 using namespace std; 10 #define MAXN 1000100 11 int n,len,a[MAXN],vis[MAXN],id[MAXN],ans[MAXN]; 12 vector<int> c[MAXN]; 13 inline int read() 14 { 15 int x=0,f=1; char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 18 return x*f; 19 } 20 bool cmp(int a,int b) 21 {return c[a].size()<c[b].size();} 22 void dfs(int x) 23 { 24 c[len].push_back(x); 25 vis[x]=1; 26 if(!vis[a[x]]) dfs(a[x]); 27 } 28 int main() 29 { 30 freopen("deepdarkfantasy.in","r",stdin); 31 freopen("deepdarkfantasy.out","w",stdout); 32 n=read(); 33 for(int i=1;i<=n;i++) a[read()]=i; 34 for(int i=1;i<=n;i++) 35 if(!vis[i]) {len++; dfs(i);} 36 for(int i=1;i<=len;i++) id[i]=i; 37 sort(id+1,id+len+1,cmp); 38 for(int i=1;i<=len;i++) 39 { 40 if(c[id[i]].size()&1) //奇环 41 { 42 int mid=c[id[i]].size()>>1; 43 mid++; 44 for(int j=0;j<c[id[i]].size();j++) 45 ans[c[id[i]][j]]=c[id[i]][(j+mid)%c[id[i]].size()]; 46 } 47 else //偶环 48 { 49 if(c[id[i]].size()!=c[id[i+1]].size()) 50 { 51 printf("-1\n"); 52 return 0; 53 } 54 else 55 { 56 for(int j=0;j<c[id[i]].size();j++) 57 { 58 ans[c[id[i]][j]]=c[id[i+1]][j]; 59 ans[c[id[i+1]][j]]=c[id[i]][(j+1)%c[id[i]].size()]; 60 } 61 i++; 62 } 63 } 64 } 65 for(int i=1;i<=n;i++) printf("%d ",ans[i]); 66 printf("\n"); 67 return 0; 68 }