ARC064-F [] [] XSY2575回転さ回文(DP)(文字列)

説明
しかし、ゲームを作るにはまっ小さなCに、彼は完全にナショナルチームの一つとして自分自身を忘れてしまった、彼は仕事のタイトルを完了するのを待っている156があります。仕事オフに行く別の日、彼は行っていなかったタイトル。彼はすぐに、最も簡単な質問の外観を拾いました。

ストリングは、いわゆるサイクリックシフトの長さによって、巡回シフト後に得られたNパリンドローム配列であることができるように「整数Nを考えると、あなたは、K列の1の間の整数であり、どのくらいのキャラクタ・セットの決定しますそれは、「1221」などの文字列を、巡回シフトが「1221」、「2211」、「2112」、「1122」4つの文字列とすることができるの終わりに(空であってもよい)接頭文字列である。結果モジュロ109 + 7」

チームはCCF小さなCがキャンセルされた資格を維持するために、あなたは今、この質問で彼を助けます。

入力

最初の行は二つの整数N、Kが含まれています

出力

出力列の数は、109の+ 7モジュロ結果の条件を満たすために。

サンプル入力

サンプル入力1

4 2

サンプル入力2

1 10

サンプル入力3

6 3

サンプル入力4

1000000000 1000000000

サンプル出力

サンプル出力1

6

サンプル出力2

10

サンプル出力3

75

サンプル出力4

875699961

ヒント

最初のサンプルでは、​​ "1111"、 "1122"、 "1221"、 "2211"、 "2112"、 "2222"、6対象の文字列があります。

まずパリンドローム配列がパリンドロームであるとして列挙パリンドローム配列を考えるので、我々は半分だけパリンドローム配列の列挙、パリンドローム配列の数である\(M ^ {(N + 1)/ 2} \) 。

各文字列は回文でなければなりません\(N \)巡回シフト後の文字列に種が、重複があるため、この計算した後、私たちは、答えよりも、それははるかに大きいでしょう。

我々は、ループ部回文配列を列挙することができ、繰り返し文字列の数を計算する方法を考えていません。

2つのケースが議論しました。

1ブロックは、奇数サイクルであります

円形断面は、パリンドローム配列がパリンドローム配列である必要があるため、する巡回シフト部の一の周期の我々の長さ(LEN \)を\が繰り返されるので、生成されます\(LEN \)新しい文字列を。

前記ループ部が偶数であります

私たちがしているようので、上記の理由により、ループ部は、限り、回文である必要があります\(/ 2 \ LEN)繰り返される長さに。

例えば、文字列\(122 111 221 \)その後、我々は2つのシフトは、文字列となる\(21122112 \)を見て、元のシリーズと同じではないが、我々は金意志回文文字列を列挙します以下のために\(21122112 \) それが繰り返さ考えられています。

次DP。

前処理してみましょう\(N- \)すべての要因、\([] \は)

我々は、セット\を(DP [I] \)セクションの最小サイクル表す([I] \)\の場合適格パリンドローム配列の数。

我々は(DP [I] \)\減算\(DP [[I]ファクター] \)を保証するために、\([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\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/2017gdgzoi44/p/11520193.html