Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 20026 | Accepted: 5376 |
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
题意就不说了吧。。。
前提:对于置换的数组(我们用next数组代替),里面的每一个元素都会存在于(有且只有)一个置换子群里面。
例如 题中数据: (4 -> 7 -> 1 -> 4)(5 -> 2 -> 3 -> 3) (8 -> 6 -> 8)(10 -> 9 -> 10)。 可找到4个子群。
思路:每个子群都有一定数目的各不相同的元素,用变量t记录子群元素个数,用son[]存储子群元素,就有son[0],son[1]...son[t-1]个元素。
那么我们可以得到如下变换规则-> 新字符数组gain[son[(k + j) % t]] = 原字符数组str[son[j]] (0 <= j <= t-1)。
公式推导过程:一个子群 有t个元素说明它的循环节为t, 经过k次置换 那么肯定就有son[(k + j) % t] = son[j];
例如 题目数据:4-1 5-1 3-1 7-1 2-1 8-1 1-1 6-1 10-1 9-1 (为了对应字符串的下标自减1) Hello+Bob+ 空格用+表示
拿子群(3 -> 6 -> 0 -> 3【已经减一】)来说,其中t = 3,son[0] = 3, son[1] = 6, son[2] = 0。
当k = 1时, { j = 0,son[(k + j) % t] = 6,gain[6] = str[3] = l
j = 1,son[(k + j) % t] = 0,gain[0] = str[6] = B
j = 2,son[(k + j) % t] = 3,gain[3] = str[0] = H
}
代码实现:
#include <cstdio> #include <cstring> #define MAX 200+66 using namespace std; char str[MAX];//将要进行变换的字符串 char gain[MAX];//变换k次后 得到的新字符串 int next[MAX];//str[i] 置换 str[next[i]] int pos[MAX];//保存当前子群元素 也就是变换过程的位置 int vis[MAX];//标记当前元素是否存在于某个子群中 (一个元素只能存在于一个置换子群中) 若可以为1否则为0 int main() { int n, k; int i, j; int t;//记录当前子群元素个数 while(scanf("%d", &n), n)//n个元素 { for(i = 0; i < n; i++) { scanf("%d", &next[i]); next[i]--;//自减一 与字符串下标协调 } while(scanf("%d", &k), k)//k次变换 注意输入后空格 { getchar(); memset(str, '\0', sizeof(str)); gets(str); for(i = strlen(str); i < n; i++) str[i] = ' ';//填充空格 memset(vis, 0, sizeof(vis));//初始化 memset(gain, '\0', sizeof(gain)); //printf("%s\n", str); for(i = 0 ;i < n; i++) { j = i;//便于运算 t = 0;//子群元素个数清 0 if(!vis[j])//不存在于 已找到的所有子群中 { while(!vis[j])//找循环节 { vis[j] = 1;//存在于当前子群 pos[t++] = j;//为当前子群保存元素 j = next[j];//下一位置 } } for(j = 0; j < t; j++)//更新 子群所有元素 { gain[pos[(j+k)%t]] = str[pos[j]];//位置为son[j] 经过k次变换 会到达位置son[(j+k)%t] } } printf("%s\n", gain); } printf("\n"); } return 0; }