zoukankan      html  css  js  c++  java
  • 【ARC064-F】【XSY2575】Rotated Palindromes(DP)(字符串)

    Description
    然而,由于小C沉迷于制作游戏,他完全忘记了自己作为国家集训队的一员,还有156道作业题等他完成。还有一天作业就要截止了,而他一题还没有做。于是他赶紧挑了一道看起来最简单的题:

    “给定一个整数N,请你求出有多少字符集为1到K之间整数的字符串,使得该字符串可以由一个长度为N的回文串循环移位后得到。所谓循环移位,就是把字符串的某个前缀(可以为空)移到字符串末尾,如"1221"循环移位可以得到"1221"、"2211"、"2112"、"1122"四个字符串。结果对109+7取模。”

    为了不让小C的集训队资格被CCF取消,请你帮助他完成这道题吧。

    Input

    第一行包含两个整数N,K。

    Output

    输出满足条件的字符串数对109+7取模的结果。

    Sample Input

    Sample Input 1

    4 2

    Sample Input 2

    1 10

    Sample Input 3

    6 3

    Sample Input 4

    1000000000 1000000000

    Sample Output

    Sample Output 1

    6

    Sample Output 2

    10

    Sample Output 3

    75

    Sample Output 4

    875699961

    HINT

    在第一个样例中,有"1111"、"1122"、"1221"、"2211"、"2112"、"2222",共6个字符串符合条件。

    我们先考虑枚举回文串,因为回文串是回文的,所以我们只用枚举回文串的一半,回文串的个数就是(m^{(n+1)/2})

    每一个回文串应该有(n)种循环移位后的到的字符串,但是这样计算后我们会发现这比答案大很多,因为有重复。

    我们考虑如何计算不重复的字符串的个数,我们可以枚举回文串的循环节。

    分两种情况讨论。

    1.循环节为奇数

    因为一个回文串的循环节必定为回文串,所以我们循环移位1个循环节的长度为(len)就会有重复,所以会产生(len)个新字符串。

    2.循环节为偶数

    因为上述的原因,循环节必定回文,我们只要有(len/2)的长度就会重复。

    比如说,串(122111221),我们移了两位之后,串变成(21122112),虽然看起来与原串并不相同,但是我们在枚举回文串的时候,也会枚举到(21122112),所以也算重复。

    接下来DP。

    我们先预处理出(n)的所有因数,(a[])

    我们设(dp[i])表示最小循环节为(a[i])时,有多少个符合条件的回文串。

    我们在(dp[i])中减去(dp[a[i]的因子]),为了保证(a[i])时最小的循环节。

    ans就直接加上回文串所贡献的字符串个数即可。

    
    #include<bits/stdc++.h>
    #define mod 1000000007
    #define int long long
    using namespace std;
    int dp[2010],cnt,n,k,a[2010],ans;
    int fastpow(int x,int y)
    {
        int sum=1;
        while(y)
        {
            if(y&1)
            {
                sum=(1ll*sum*x)%mod;
            }
            x=(1ll*x*x)%mod;
            y>>=1;
        }
        return sum;
    }
    signed main()
    {
        scanf("%lld%lld",&n,&k);
        for(int i=1;i*i<=n;i++)//枚举因子
        {
            if(n%i==0)
            {
                a[++cnt]=i;
                if(i*i!=n)
                {
                    a[++cnt]=n/i;
                }
            }
        }
        sort(a+1,a+cnt+1);
        for(int i=1;i<=cnt;i++)
        {
            dp[i]=fastpow(k,(a[i]+1)/2);//有多少个回文串
            for(int j=1;j<i;j++)
            {
                if(a[i]%a[j]==0)//去重
                {
                    dp[i]=(dp[i]-dp[j]+mod)%mod;
                }
            }
            if(a[i]&1)//统计答案
            {
                ans=(ans+dp[i]*a[i])%mod;
            }else{
                ans=(ans+dp[i]*(a[i]/2))%mod;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    个人第三次作业——原型设计
    《构建之法》团队作业第一次
    vsCode如何将结果输入到调试控制台
    Beta-冲刺第三天
    Beta版本(有更改)
    Beta冲刺-第二天
    Beta冲刺—第一天
    个人作业-测试
    团队项目—系统设计
    团队项目-需求分析
  • 原文地址:https://www.cnblogs.com/2017gdgzoi44/p/11520193.html
Copyright © 2011-2022 走看看