UVa:306 Cipher

这个题去年就看到了,但是用模拟的办法超时了。如果每次模拟都记录下字符串还会内存超限。后来得知是置换群。每个字符的出现都是有周期的,这样整个串的周期就是所有字符周期的最小公倍数数。如果求了串的周期,k取模之后再模拟,还是会超时。正确的办法是k对每个字符的周期取模,然后对字符操作。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define MAXN 5000000
//ios::sync_with_stdio(false);
using namespace std;
int num[205],n,r[205];
void Init()
{
    for(int i=1; i<=n; ++i)
    {
            int now=num[i],ed=i,cir=1;
            while(now!=ed)
            {
                cir++;
                now=num[now];
            }
            r[i]=cir;
    }
}
void Set_text(char *str)
{
    int l=strlen(str+1);
    for(int i=l+1; i<=n; ++i)
        str[i]=' ';
    str[n+1]=0;
}
void solve(char *str1,char *str2,int k)
{
    for(int i=1; i<=n; ++i)
    {
        int ed=(k-1)%r[i]+1,now=i;
        for(int j=0; j<ed; ++j)
            now=num[now];
        str2[now]=str1[i];
    }
    str2[n+1]=0;
}
int main()
{
    while(scanf("%d",&n)&&n)
    {
        for(int i=1; i<=n; ++i)
            scanf("%d",&num[i]);
        Init();
        char str1[205],str2[205];
        int k;
        while(scanf("%d",&k)&&k)
        {
            char c;
            getchar();
            gets(str1+1);
            Set_text(str1+1);
            solve(str1,str2,k);
            printf("%s\n",str2+1);
        }
        printf("\n");
    }
    return 0;
}


 

你可能感兴趣的:(数学,置换群)