/*
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次
最新推荐文章于 2018-02-05 14:16:31 发布