1. 程式人生 > >牛客練習賽35 - B背單詞 - 3維的dp

牛客練習賽35 - B背單詞 - 3維的dp

題目描述

winterzz1準備考4級了,現在winterzz1決定把世界上所有單詞都背一遍,winterzz1發現任意一個單詞最多有A個連續的母音,最多有B個連續的子音。且單詞最長長度為N,winterzz1問你在滿打滿算的情況他需要背多少單詞???

輸入描述:

首先輸入一個T(T<=100),表示有T組案例,每組案例依次輸入三個正整數N,A,B,N<=5000,A<=50,B<=50;

輸出描述:

輸出winterzz1最多需要背多少單詞,結果mod(10^9+7)

示例1

輸入

複製

2
2 2 2
500 20 30

輸出

複製

702
175540856

備註:

母音字母為a,e,i,o,u,其餘21個字母均為子音

思路:

開一個dp[5005][2][55]的陣列

dp[i][j][k]:=判斷到第i位,第i位的元素是j(j==0表示母音,j==1表示子音),重複了k次有幾個單詞。

eg、dp[1][0][1]=5。第1位是母音有5種;dp[1][1][1]=21。第1位是子音有21種

dp[2][0][2]=25。第2位是母音,且第1位也是母音有25種。

遞推方程:

for(int j=1;j<=min(b,i-1);j++)dp[i][0][1]=(dp[i][0][1]+dp[i-1][1][j]*5)%mod;

第i位是母音,且第i-1位不是母音的情況,也就是說第i-1位是子音的所有情況之和*5

for(int j=1;j<=min(a,i-1);j++)dp[i][1][1]=(dp[i][1][1]+dp[i-1][0][j]*21)%mod;

第i位是子音,且第i-1位不是子音的情況,也就是說第i-1位是母音音的所有情況之和*21

那麼我們知道動態規劃是由已知到未知的,怎麼賦初值呢?

對於每個i,我們可以求出從母音重複個數從2到a的情況,和子音重複個數為從2到b的情況,然後用遞推方程求出在i位置上之重複1次的情況。

for(int j=2;j<=min(a,i);j++){//初始化,到第i個位置時連續2個母音及以上的情況
    dp[i][0][j]=dp[i-1][0][j-1]*5%mod;
}
for(int j=2;j<=min(b,i);j++){//初始化,到第i個位置時連續2個子音及以上的情況
    dp[i][1][j]=dp[i-1][1][j-1]*21%mod;
}

(dp小白只能這樣理解了qwq,每次推的時候都懵的一批,不知道怎麼賦初值,不會推qwq)

程式碼如下:

#include<iostream>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<sstream>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int N=5005,mod=1e9+7;
ll dp[N][2][55];
int main(){
    int t,a,b,n;
    scanf("%d",&t);
    while(t--){
        memset(dp,0,sizeof(dp));
        scanf("%d%d%d",&n,&a,&b);
        dp[1][0][1]=5;dp[1][1][1]=21;
        for(int i=2;i<=n;i++){
            for(int j=2;j<=min(a,i);j++){
                dp[i][0][j]=dp[i-1][0][j-1]*5%mod;
            }
            for(int j=2;j<=min(b,i);j++){
                dp[i][1][j]=dp[i-1][1][j-1]*21%mod;
            }
            for(int j=1;j<=min(b,i-1);j++)dp[i][0][1]=(dp[i][0][1]+dp[i-1][1][j]*5)%mod;
            for(int j=1;j<=min(a,i-1);j++)dp[i][1][1]=(dp[i][1][1]+dp[i-1][0][j]*21)%mod;
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=a;j++){
                ans=(ans+dp[i][0][j])%mod;
            }
            for(int j=1;j<=b;j++){
                ans=(ans+dp[i][1][j])%mod;
            }
        }
        printf("%lld\n",ans%mod);
    }
}