zoukankan      html  css  js  c++  java
  • POJ3590 The shuffle Problem [置换+dp]

    The shuffle ProblemThe shuffle Problem


    Descriptionmathcal{Description}

    给出正整数NN, N<=100N<=100, 输出长度为 NN 的置换的 最长周期, 并请输出满足条件的 字典序最小 的置换 .


    Solutionmathcal{Solution}

    最初想法
    整个序列的循环节周期长度为所有 子循环节 周期长度 的最小公倍数 .

    思维卡点: 每个子循环节的周期长度怎么求呢 ?


    正解部分
    原来每个子循环节的周期长度是确定的 :

    • 作为子循环节不能被划分成其他更小的子循环节
    • 经过观察, 每个不可划分的子循环节周期长度都等于其本身长度,

    所以得出结论:   color{red}{子循环节的周期长度 等于 本身长度},

    到此, 问题就转化为: 将数NN划分为若干份, 使 LCMLCM 尽量大.


    F[i,j]F[i,j] 表示 将 ii 分为 jj 份所得到的最大 LCMLCM,
    F[i,j]=max{ lcm(F[ik,j1],  k), F[i,j] }F[i,j]=max{ lcm(F[i-k,j-1], k), F[i,j] }
    转移复杂度 O(N3)O(N^3) .


    ?如何输出字典序最小的方案?

    首先最优值 AnsAns 已经被前面的 DpDp 解决,
    这个 AnsAns 为所有区间长度的 LCMLCM,
    则将其 color{red}{分解质因数}, 得到 p1a1,p2a2,p3a3...pmamp_1^{a_1}, p_2^{a_2},p_3^{a_3}...p_m^{a_m},
    每个带幂质数都代表着一个区间, 长度分别为 p1a1,p2a2,p3a3...pmamp_1^{a_1}, p_2^{a_2},p_3^{a_3}...p_m^{a_m},.

    可能还会剩余一些 11, 虽说对 LCMLCM 没有贡献, 但还是要输出的, 输出 Np1a1p2a2p3a3...pmamN-p_1^{a_1}-p_2^{a_2}-p_3^{a_3}...-p_m^{a_m}11 在前面 color{red}{保证字典序最小}
    尽量将小的放到前面, 可以 color{red}{保证字典序最小}, 拿纸画一下就出来了.


    Codemathcal{Code}

    #include<cstdio>
    #include<algorithm>
    #define reg register
    
    const int maxn = 108;
    
    int T;
    int N;
    int cnt[maxn];
    int F[maxn][maxn];
    int Pre[maxn][maxn];
    int p[] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107};
    
    int Gcd(int a, int b){ return !b?a:Gcd(b, a%b); }
    int Lcm(int a, int b){ return a/Gcd(a, b) * b; }
    
    void Work(){
            scanf("%d", &N);
            printf("%d ", F[N][0]);
            int tmp = F[N][0], Ps = 0;
            for(reg int i = 1; i <= 26; i ++){
                    cnt[i] = 1;
                    while(tmp % p[i] == 0) cnt[i] *= p[i], tmp /= p[i];
                    if(cnt[i] == 1) cnt[i] = 0;
                    Ps += cnt[i];
            }
            int t = N - Ps;
            for(reg int i = 1; i <= t; i ++) printf("%d ", i);
            t ++;
            std::sort(cnt+1, cnt+26+1);
            for(reg int i = 1; i <= 26; i ++){
                    if(!cnt[i]) continue ;
                    int tmp = t;
                    for(reg int j = 1; j < cnt[i]; j ++) printf("%d ", t+j);
                    printf("%d ", tmp);
                    t += cnt[i];
            }
            printf("
    ");
    }
    
    int main(){ 
            for(reg int i = 1; i <= 105; i ++){
                    F[i][1] = i;
                    for(reg int j = 2; j <= i; j ++)
                            for(reg int k = 1; k <= i; k ++)
                                    F[i][j] = std::max(Lcm(F[i-k][j-1], k), F[i][j]);
            }
            for(reg int i = 1; i <= 105; i ++) 
                    for(reg int j = 1; j <= i; j ++) F[i][0] = std::max(F[i][0], F[i][j]);
            scanf("%d", &T);
            while(T --) Work();
            return 0;
    }
    
  • 相关阅读:
    go第二天
    go第一天
    engish
    english
    git 生成公钥
    tp5 验证码
    css处理文本折行截断
    数组对象总结(牢记)
    全局css样式
    Flexbox 弹性盒子布局
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822581.html
Copyright © 2011-2022 走看看