【HDU1439Cipher】循环群

Cipher

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 319    Accepted Submission(s): 141


Problem Description
Bob and Alice started to use a brand-new encoding scheme. Surprisingly it is not a Public Key Cryptosystem, but their encoding and decoding is based on secret keys. They chose the secret key at their last meeting in Philadelphia on February 16th, 1996. They chose as a secret key a sequence of n distinct integers, a1 ; . . .; an, greater than zero and less or equal to n. The encoding is based on the following principle. The message is written down below the key, so that characters in the message and numbers in the key are correspondingly aligned. Character in the message at the position i is written in the encoded message at the position ai, where ai is the corresponding number in the key. And then the encoded message is encoded in the same way. This process is repeated k times. After kth encoding they exchange their message.

The length of the message is always less or equal than n. If the message is shorter than n, then spaces are added to the end of the message to get the message with the length n.

Help Alice and Bob and write program which reads the key and then a sequence of pairs consisting of k and message to be encoded k times and produces a list of encoded messages. 

 

Input
The input file consists of several blocks. Each block has a number 0 < n <= 200 in the first line. The next line contains a sequence of n numbers pairwise distinct and each greater than zero and less or equal than n. Next lines contain integer number k and one message of ascii characters separated by one space. The lines are ended with eol, this eol does not belong to the message. The block ends with the separate line with the number 0. After the last block there is in separate line the number 0. 
 

Output
Output is divided into blocks corresponding to the input blocks. Each block contains the encoded input messages in the same order as in input file. Each encoded message in the output file has the lenght n. After each block there is one empty line.
 

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
 

Source

题解:

题目大意

Bob和Alice想用一种新的加密方式,他们编码和译码都是依靠秘密钥匙,秘密钥匙选用一串数字a1,……an(0<ai<=n),编码要求:将信息(长度不大于n,如果小于n请自己补上空格)中i位置上的字符放到ai位置上。这个过程经过K遍之后就成了加密后的信息。现在要求你写一个程序帮他们实现编码。

题目分析

       拿到这个题可能不知道如何下手,唯一能想到的就是直接模拟。但有没有注意到他没有给你k的范围。如果k很大,模拟的结果就是TLE,所以这个方式是行不通的。有没有注意到他是将i位置上的字符放在ai位置上,可以想到用置换群做。以sample的数据为例:

i: 1   2   3  4   5   6  7   8   9   10

ai: 4  5   3   7  2   8   1  6   10   9

信息:  H  e    l   l  o       B   o   b

 

我们先模拟一下:

1次  i: 1   2   3  4   5   6  7   8   9   10

信息  :  B   o   l   H   e   o   l           b

 

2次  i: 1   2   3  4   5   6  7   8   9   10

信息  :  l   e    l   B   o       H  o    b   

 

3次  i: 1   2   3  4   5   6  7   8   9   10

信息  :  H   o  l   l   e    o   B          b

 

不知道大家发现没有在交换过程中,位置i为1,4,7的轮回,2和5交换,3不动,6和8换,9和10换。在看看我们的秘密钥匙:

i: 1   2   3  4   5   6  7   8   9   10

ai: 4  5   3   7  2   8   1  6   10   9

把它看成一个置换群,则可以找出循环(轮换):

(1 4  7)(2  5)(3)(6  8)(9 10)

  这和我们上面找出的规律是否有一定联系呢?

每次操作其实都是将这个循环右移,当操作循环长度L次时回到原来状态。

那么我们只要做k%L次就够了,但如果还是用模拟还是不行的,我们要运到群换群的幂,关于幂运算,具体看潘震皓的论文。这里我只是提一下他的算法实现:

l For 源置换中每一个循环

n  For 环中每一个未标记元素

u  Do

l  做上标记

l  放入结果数组

l  前进k格

u  Until 回到这个元素

u  将结果数组中的元素取出,得到的环,便是目标置换包含的一个循环

 

 

兔子


#define DeBUG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <sstream>
#include <map>
#include <list>
#include <bitset>
using namespace std ;
#define zero {0}
#define INF 0x3f3f3f3f
#define EPS 1e-6
#define TRUE true
#define FALSE false
typedef long long LL;
const double PI = acos(-1.0);
//#pragma comment(linker, "/STACK:102400000,102400000")
inline int sgn(double x)
{
    return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);
}
#define N 1100
char input[N], output[N];
//计算循环群
int num[N], array[N][N], cycle[N];
//初始数组,循环hash数组,循环次数
void func(const int &n)
{
    memset(cycle, 0, sizeof(cycle));
    for (int i = 0; i < n; i++)
        array[0][i] = i;
    int tmp = n;
    int tm = 1;//循环次数
    while (tmp)
    {
        for (int i = 0; i < n; i++)
            if (!cycle[i])//没有完成计算循环进行hash操作
                array[tm][num[i]] = array[tm - 1][i];
        for (int i = 0; i < n; i++)//完成循环记录
            if (!cycle[i] && array[tm][i] == array[0][i])
            {
                cycle[i] = tm;
                --tmp;
            }
        ++tm;//循环+1
    }
}
int main()
{
#ifdef DeBUGs
    freopen("C:\\Users\\Sky\\Desktop\\1.in", "r", stdin);
#endif
    int n, k;
    while (scanf("%d", &n), n)
    {
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &num[i]);
            --num[i];
        }
        func(n);
        while (scanf("%d", &k), k)
        {
            getchar();
            gets(input);
            for (int i = strlen(input); i < n; i++)
                input[i] = ' ';
            memset(output, ' ', sizeof(output));
            for (int i = 0; i < n; i++)
            {
                output[i] = input[array[k % cycle[i]][i]];
                //次数对循环取模得到对应变量,分循环群
            }
            output[n] = '\0';
            puts(output);
        }
        printf("\n");
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值