BC - King's Order - 數位DP

題意:給你一個字符串的長度n在這個n長的字符串裏不能出現連續超過3次的的字符。問符合該條件的字符串有幾個。

思路:

一個比較暴力的dp方法:

開一個三維dp數組dp[串長度][添加字符前的最後一個字符][最後一個字符重複數]

這樣我們對於每個長度枚舉新添加的一個字符和倒數第二個,如果新加字符與倒數第二個字符相同我們對於每一個重複情況都向下遞推累加。如果不同我們讓dp[當前長度][最後一個字符][重複數爲1] 累加倒數第二個字符所有重複數情況。最後對於dp[n][i][j](0<=i<=25,1<=j<=3)求和得解;

一個很巧妙的dp:

其實之前種dp中中間狀態可以不用考慮,我們使用一個二維數組讓每次長度的遞推包含了對應增加的新字符。對於每一次長度增加枚舉最後一個字符的重複狀態,對於重複1和2次我們可以選擇添加一個同樣字符所以dp[i+1][j+1] = dp[i+1][j+1]+dp[i][j] %MOD。於此同時新加字符也可能與當前最後一個字符不同所以dp[i+1][1] = dp[i+1][1] + dp[i][j]*25%MOD兩個遞推在一次枚舉時同時進行 。這樣會極大的優化dp過程。

兩種方法分別如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
using namespace std;

long long dp[2010][27][4];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(int i=0;i<26;i++)
        {
            dp[1][i][1]=1;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<26;j++)
            {
                for(int k=0;k<26;k++)
                {
                    if(j==k)
                        for(int l=1;l<=3;l++)
                        {
                            dp[i][j][l] = (dp[i][j][l]+dp[i-1][j][l-1]) % MOD;
                        }
                    else
                        for(int l=1;l<=3;l++)
                        {
                            dp[i][k][1] = (dp[i][k][1]+dp[i-1][j][l]) % MOD;
                        }
                }
            }
        }
        long long ans=0;
        for(int i=0;i<26;i++)
        {
            for(int j=1;j<=3;j++)
                ans = (ans+dp[n][i][j]) %MOD;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
using namespace std;

long long dp[2010][4];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        dp[1][1]=26;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=3;j++)
            {
                if(j!=3)
                    dp[i+1][j+1] = (dp[i+1][j+1]+dp[i][j]) % MOD;
                dp[i+1][1] = (dp[i+1][1]+dp[i][j]*25) % MOD;
            }
        }
        long long ans=0;
        for(int i=1;i<=3;i++)
        {
            ans = (ans+dp[n][i]) % MOD;
        }
        printf("%lld\n",ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章