• UVA306 Cipher[循环节]


    UVA306 CipherUVA306 Cipher


    Descriptionmathcal{Description}

    Bob和Alice开始使用一种全新的编码方案。令人惊讶的是,这不是公共关键字密码系统,他们的编码和解码都是基于一种特殊的密码。他们于1996年2月16日在费城的最后一次会议上确定了他们的密码。他们把密码定为一个含有n个不同整数的数列,a1,…,an(0<ai<=n)。解码根据以下原则:把信息写在密钥的下方,使信息中的字符和密钥中的数字相应对齐。在位置i处的消息字符被写入位置ai处,其中ai是密钥中相应的编号。得到的消息以相同的方式继续被编码。重复这个过程k次,第k个编码即是最后答案。

    消息的长度总是小于或等于n。若消息长度小于n,用空格补齐。

    请你帮助Alice和Bob编写一个读取密钥的程序,进行k次编码,产生编码消息。

    N&lt;=10,000N&lt;=10,000


    Solutionmathcal{Solution}

    最初想法
    求出整个置换的循环节长度, 对于后面的每个询问, 都模循环节后暴力进行模拟.
    时间复杂度 O(N)O(循环节大小*N),
    LuoguLuoguACcolor{green}{AC},
    V JudgeV JudgeTLEcolor{blue}{TLE}.


    正解部分
    由于 整个置换 的循环节大小为 所有 子循环节 大小的 LCMLCM,
    导致时间复杂度为 O(LCMN)O(LCM*N), 其中 LCMLCM 的上限为 N!N!, 在luogu竟然还能A.

    但若求出每个位置单个的循环节, 对每个询问就可以 O(sizeN)O(size*N) 得到答案, sizesize 的上限为 NN.

    求出整个置换的循环节大小需要 2500ms2500ms 左右,
    但是求出单个循环节大小仅需要 20ms20ms.


    实现部分
    没什么好说的.


    Codemathcal{Code}

    #include<cstdio>
    #include<cstring>
    #define reg register
    
    const int maxn = 205;
    
    int N;
    int K;
    int A[maxn];
    int B[maxn];
    int l[maxn];
    
    char S[maxn];
    char Ans[maxn];
    
    void Work(){
            getchar();
            scanf("%[^
    ]", S+1);
            int len = strlen(S+1);
            while(len < N) S[++ len] = ' ';
            for(reg int i = 1; i <= N; i ++) B[i] = i;
            for(reg int i = 1; i <= N; i ++){
                    int tmp = K % l[i];
                    while(tmp --) B[i] = A[B[i]];
            }
            for(reg int i = 1; i <= N; i ++) Ans[B[i]] = S[i];
            for(reg int i = 1; i <= N; i ++) printf("%c", Ans[i]);
            printf("
    ");
    }
    
    int main(){
            while(~scanf("%d", &N) && N){
                    for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]);
                    for(reg int i = 1; i<= N; i ++){
                            int t = i, to = A[i]; l[i] = 1;
                            while(to != t) l[i] ++, to = A[to];
                    }
                    while(~scanf("%d", &K) && K) Work();
                    printf("
    ");
            }
            return 0;
    }
    
    
    
  • 相关阅读:
    得不到的永远在骚动
    这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧【转】
    Windows CMD命令大全【转】
    创业为什么选择北上广?
    为什么你还把时间浪费在无效人脉社交上?
    五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程
    mysql分区操作
    程序员常用网站
    4种提升SQL查询性能的知识
    获得局域网内其他成员的信息
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822583.html
Copyright © 2020-2023  润新知