poj 1026 Cipher

来源:互联网 发布:时间矩阵图怎么落实 编辑:程序博客网 时间:2024/04/29 02:38
 /*  * poj 1026 Cipher    题目大意:        Bob 和 Alice约定了一种加密算法。该算法的密钥是一组选定n个不同的数字,        {a1,a2...an | 1<=ak<=n}。加密步骤具体如下:        1、输出密钥序列        2、在密钥序列下方,对应的输出需要加密的字串        3、按照上方标号的顺序输出字串即密文        举例如下:        4 5 3 7 2 8 1 6 10 9 -- 密钥序列        H e l l o   B o b    -- 原文        B o l H e o l      b -- 一次加密后的密文        密文可以按照上述方式被多次加密。本题就是要求出给定加密次数后的密文是什么样子的?    解题思路:        模拟题,找规律。        1、密文序列决定了每个位置只可能固定出现几个字符,以上例的首字符为例。           a、第i次密文输出的首字符,必然i-1次密文的第7个位置的字符。           b、而i-1次密文的第7个位置的字符,必然是i-2次密文第4个位置的字符           c、而i-2次密文的第4个位置的字符,必然是i-3次密文第1个位置的字符           至此,我们发现第i次密文输出的首字符与第i-3次密文的首字符是同样的,也就是说           每加密3次,首字符会重复出现一次。以上首字符的变化可以总结如下:           i-3  i-2  i-1   i   i+1  i+2  i+3            1 -> 4 -> 7 -> 1 -> 4 -> 7 -> 1           以上可以看出,第1、4、7位置处的字符均每3轮重复一次。         2、其他位置的也可以推出类似的规律,针对每个位置推导出重复周期,即可            很容易的得到最后的密文是什么样子的    另注:        本程序提交结果是797ms,看discuss里说用置换群做,只要16ms,差距啊!        不过,没听过什么置换群,看到一个哥们如下说:        <本题用置换群做,单独考虑每个字母n次置换后的位置,建议不懂的同学去看下黑书248页>        这个置换群应该很NB的样子,去学一下。 */#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>namespace {    using namespace std;    const int N_MAX = 200;    int keys[N_MAX+1]; // 密钥存储    int periods[N_MAX+1]; // 每个位置处的周期值    int previous[N_MAX+1];// 每个位置对应的前一次位置} int main(){    char message[N_MAX+2]; // 消息        int n, k;    while (scanf("%d", &n) && n!=0)    {        for (int i=1; i<=n; i++)        {            scanf("%d", &keys[i]);                        previous[keys[i]] = i; // 前一个位置赋值            periods[i] = 0; // 周期初始化        }        for (int i=1; i<=n; i++)        {            if (periods[i]!=0) continue; // 处理过,不在处理            // 计算i位置处字符的周期值            int p=1, t=previous[i];;            while (t != i)            {                ++p;                t = previous[t];            }            // 循环内的所有元素周期值是一样的            periods[i]=p;            t=previous[i];            while (t != i)            {                periods[t] = p;                t = previous[t];            }        }        // 读入并加密消息        while (scanf("%d", &k) && k!=0)        {            getchar(); // 丢掉首部的空格            gets(&message[1]); // 读入消息            for (int i = strlen(&message[1])+1; i<=n; i++)            {                message[i] = ' '; // 消息长度不足n时,补齐空格            }            int r=0;            for (int i=1; i<=n; i++)            {                r = k%periods[i]; // 计算余数                                int t=i;                for (int j=0; j<r; j++) // 查找r轮前的字符索引                {                    t = previous[t];                }                printf("%c", message[t]); // 打印            }            printf("\n"); // 消息打印完毕,换行        }        printf("\n"); // After each block there is one empty line.     }        return 0;}


原创粉丝点击