大致题意:Bob and Alice为多个长度为n的信息加密,信息的长度可能小于n,不足n的字符补成空格。先给出n,再给出一个长度为n的数组num[]即加密方式,将原字符串下标为i的字符和下标为num[i]的字符交换。然后给出加密次数和要加密的字符串(多组数据),求出加密后的字符串。具体输入输出格式请参照原题。
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 20000/10000K (Java/Other)
样例:
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
思路:一组数据之间的交换应该还是可以用置换解决,关键求出循环节个数和每个循环中的元素。每个循环节可以搜索出来,同时也能够记录每个循环,难度不大,另外如果一个循环长度为l,那么它加密l次就回到原来初态,所以加密次数对l取余能缩短处理时间。这个题输入输出都比较麻烦,要注意几个细节,每组数据要补全空格,每个case后输出一个空行等等。
貌似有别的解法,没仔细去研究,看到置换就直接去套了,感觉有置换做应该是最快的了。跑了800+ms,够慢的,把循环节个数和循环长度和加密次数都代成200也不超过10^7,看来测试数据够多的。这里应该有一部分代码风格的原因,另外可能有优化的细节没注意,YM 0ms AC的。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int MAXNUM=205; 5 int num[MAXNUM],cir[MAXNUM][MAXNUM],cnt,n,times; 6 bool vis[MAXNUM]; 7 char mesg[MAXNUM]; 8 int circle(){ //求出循环节的个数cnt,每个循环节cir的长度len和包含的元素 9 int i,j,cnt=0; 10 memset(vis,0,sizeof(vis)); 11 for(i=1;i<=n;i++){ 12 int len=0,temp=i; 13 while(!vis[temp]){ 14 vis[temp]=true; 15 cir[cnt][++len]=temp; 16 temp=num[temp]; 17 } 18 if(len!=0){ 19 cir[cnt][0]=len; 20 cnt++; 21 } 22 } 23 return cnt; 24 } 25 void solve(){ //用求出的置换对信息加密,由于每个循环节所表示的置换可以拆成多个对换,所不断以对cir[i][1]和cir[i][j]交换就等价于原置换。 26 int i,j; 27 for(i=0;i<cnt;i++){ 28 int len=times%cir[i][0]; 29 while(len--){ 30 for(j=2;j<=cir[i][0];j++){ 31 char temp=mesg[cir[i][1]]; 32 mesg[cir[i][1]]=mesg[cir[i][j]]; 33 mesg[cir[i][j]]=temp; 34 } 35 } 36 } 37 for(i=1;i<=n;i++)printf("%c",mesg[i]); 38 printf("\n"); 39 } 40 int main(){ 41 int i,j; 42 while(scanf("%d",&n)&&n){ 43 for(i=1;i<=n;i++){ 44 scanf("%d",&num[i]); 45 } 46 cnt=circle(); 47 while(scanf("%d",×)&×){ 48 memset(mesg,0,sizeof(mesg)); 49 gets(mesg); 50 for(i=strlen(mesg);i<=n;i++)mesg[i]=' '; 51 mesg[n+1]='\0'; 52 solve(); 53 } 54 printf("\n"); 55 } 56 return 0; 57 }