【解题报告】POJ 1026 Cipher -- 置换群 轮换k次

/*
	POJ 1026 Cipher -- 置换群 轮换k次
	给一个序列A{a1=4 a2=5 a3=3 a4=1 a5=2}和很多字符串
	CDFET ...
	按照A转换为 ETFCD (第一个到第四个,以此类推...)
	再给一个k表示按照A序列规则转换k次
	求最后的字符串
	先求循环节
	1 4 
	2 5
	3
	循环节长度的最小公倍数为 字符串转换的周期
	这样在循环节内就知道哪个字母在哪个位置了。
	加周期模一下循环节的长度即可

*/

#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <ctime>
#include <cmath>
#define CLR(a,v) memset(a,v,sizeof(a))
using namespace std;
typedef long long ll;

const int N = 2e2 + 5;
const char blank = ' ';
ll gcd(ll a , ll b){
	return b ? gcd(b,a%b) : a ;
}

char str[N];
int B[N];
bool vis[N];
vector <int > v[N];
void GetCircle(int x,int cnt){
	if(vis[x])return ;
	vis[x] = 1;
	v[cnt].push_back(x);//cout << x << " ";
	GetCircle(B[x] , cnt);
}

int main(){
	freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);

	int n,k;
	while(scanf("%d",&n),n){
		for(int i = 1 ; i<= n ;i++)
			scanf("%d",&B[i]);
		int cnt = 0;
		int t = 1;
		CLR(vis,0);
		for(int i = 0 ; i < N ; i++)
			v[i].clear();
		for(int i = 1 ; i <= n ; i++){
			if(!vis[i]){
				GetCircle(i,cnt++); //cout << endl;
				t = t / gcd(v[cnt-1].size() , t) * v[cnt-1].size();
			}
		}

		while(scanf("%d",&k),k){
			getchar();
			k %= t;
			CLR(str , blank);
			char *pstr =  str + 1;
			gets(str + 1);
			if(k==0){cout << str + 1 << endl;continue;}
			int len = strlen(str + 1);
			pstr[len] = blank; pstr[n] = '\0';
			char ans[N];
			for(int i = 0 ; i < cnt ; i++){
				for(int j = 0 ; j < v[i].size() ; j++){
					ans[ v[i][ (j+k) % v[i].size() ] ] = str[v[i][j]];
				}
			}
			ans[n+1] = '\0';
			cout << ans+1 << endl;
		}cout << endl;
	}
	return 0;
}


/*
20
5 1 6 2 7 3 9 4 10 19 20 15 13 17 14 16 18 11 12 8
65132 CDFETR
23423       DF DF DfffF
123 WERS   D
0
0

  F  R T  D      E C
    D   D  fDFff F F
     R    W  D  SE  

*/

你可能感兴趣的:(【解题报告】POJ 1026 Cipher -- 置换群 轮换k次)