总时间限制: 1000ms 内存限制: 65536kB
描述
Bob 和 Alice 开始使用一种全新的编码系统。它是一种基于一组私有钥匙的。他们选择了n个不同的数a1 , . . .,an,它们都大于0小于等于n。 机密过程如下:待加密的信息放置在这组加密钥匙下,信息中的字符和密钥中的数字一一对应起来。信息中位于i位置的字母将被写到加密信息的第ai个位置,ai 是位于i位置的密钥。加密信息如此反复加密,一共加密 k 次。 信息长度小于等于n。如果信息比 n 短, 后面的位置用空格填补直到信息长度为n。 请你帮助 Alice 和 Bob 写一个程序,读入密钥,然后读入加密次数 k 和要加密的信息,按加密规则将信息加密。
输入
输入包括几块。每块第一行有一个数字n, 0 < n <= 200.接下来的行包含n个不同的数字。数字都是大于0小于等于n的。下面每行包含一个k和一个信息字符串,它们之间用空格格开。每行以换行符结束,换行符不是要加密的信息。每个块的最后一行只有一个0。 最后一个块后有一行,该行只有一个0。
输出
输出有多个块,每个块对应一个输入块。每个块包含输入中的信息经过加密后的字符串,顺序与输入顺序相同。所有加密后的字符串的长度都是 n。每一个块后有一个空行。
样例输入
10
4 5 3 7 2 8 1 6 10 9
1 Hello Bob
1995 CERC
0
0
样例输出
BolHeol b
C RCE
这道题真的……一直超时一直超时一直超时,写的心力交瘁。
暴力解决会超时!
最后(在大佬的指导下),利用变换是固定周期的,只在固定数量的位置间变化的规律(比如1到3再到7后又会回到1,固定数量为3,就是周期为3)所以就用count数组储存这个周期,比如count[1],count[3],count[7]都存3,然后变换的时候只需要变换k%count[i]次就行,这样就可以大大减少运算。
代码段
#include <string>
#include <iostream>
using namespace std;
void preprocess(int *key, int n, int *count)
{
for (int index = 1; index <= n; index++) {
int begin = index;
int next = begin;
int num = 1;
while (key[next] != begin) {
num++;
next = key[next];
}
count[index] = num;
}
}
int main() {
int key[201];
int final_position[201];
int count[201];
int n;
cin >> n;
while (n != 0) {
for (int i = 1; i <= n; i++)
cin >> key[i];
preprocess(key, n, count);
int k;
cin >> k;
while (k != 0) {
string s;
getline(cin, s);
for (int index = 1; index <= n; index++) {
int Final = index;
int num = k % count[index];
for (int i = 0; i < num; i++)
Final = key[Final];
final_position[Final] = index;
}
int length = s.length();
for (int i = 1; i <= n; i++) {
if (final_position[i] > length - 1)
cout << ' ';
else
cout << s[final_position[i]];
}
cout << endl;
cin >> k;
if (k == 0)
cout << endl;
}
cin >> n;
}
return 0;
}