Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 19228 | Accepted: 5148 |
Description
Input
Output
Sample Input
10 4 5 3 7 2 8 1 6 10 9 1 Hello Bob 1995 CERC 0 0
Sample Output
BolHeol b C RCE
Source
根据一个n个数置换,把一个字符串上的元素进行变换K次,输出K次变换后的字符串,如果字符串的长度不为n,那么在字符串末尾加空格使其长度为n。
比如样例
4 5 3 7 2 8 1 6 10 9
1 Hello Bob
意思是Hello Bob 根据置换规则置换一次, 比如H它是字符串中的第一位,现在要变成字符串中的第4位,依次类推。
1 2 3 4 5 6 7 8 9 10
4 5 3 7 2 8 1 6 10 9 循环节有 (1,4,7) (2,5) (3) (6,8) (9,10),对整个字符串变换,可以分别对每个循环节进行变换
有这样一个性质:
设,T^k=e (T为一循环,e为单位置换),那么k的最小正整数解为T的长度。也就是一个循环节循环它的长度次数,可以回到本身,那么题目中的变换K次等价于变换K%循环节长度 次数。
因此我们可以求出一个置换里面循环节的个数和所有的循环节的长度以及每个循环节所包含的元素。然后再对每个循环节进行K%(本个循环节的长度)次模拟。
参考:
http://www.cnblogs.com/mcflurry/archive/2012/06/24/2560467.html
http://www.cnblogs.com/kuangbin/archive/2012/09/03/2669660.html
代码:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; int n; int num[210];//输入的整数 char s[210];//输入的字符串 bool vis[210];//计算循环节时用到 int cir[210][210];//cir[i][0]表示第i个循环节的长度,cir[i]表示第i个循环节里面包括什么元素 int cnt;//循环节的个数 int k;//循环的个数 int getCircle() { cnt=0; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { int len=0;//循环节的长度 int temp=i; while(!vis[temp]) { cir[cnt][++len]=temp; vis[temp]=true; temp=num[temp]; } if(len)//别忘了加这一句话 cir[cnt++][0]=len; } return cnt; } void solve() { for(int i=0;i<cnt;i++)//对于每个循环节 { int len=k%cir[i][0];//需要循环的次数。 while(len--)//模拟len次交换 { for(int j=2;j<=cir[i][0];j++) { char temp=s[cir[i][1]]; s[cir[i][1]]=s[cir[i][j]]; s[cir[i][j]]=temp; } } } for(int i=1;i<=n;i++) cout<<s[i]; cout<<endl; } int main() { while(cin>>n) { for(int i=1;i<=n;i++) cin>>num[i]; cnt=getCircle(); while(cin>>k&&k) { gets(s);//k后面紧跟着地空格为s[0]。 for(int i=strlen(s);i<=n;i++) s[i]=' '; s[n+1]='\0'; solve(); } cout<<endl; } return 0; }
[ACM] POJ 1026 Cipher (组合数学,置换),布布扣,bubuko.com
[ACM] POJ 1026 Cipher (组合数学,置换)
原文:http://blog.csdn.net/sr_19930829/article/details/38168927