版权声明:本文为博主原创文章,转载请说明出处。 https://blog.csdn.net/xianpingping/article/details/85412814
链接:https://ac.nowcoder.com/acm/contest/326/B
来源:牛客网
题目描述
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;然后就想状态,之前做过类似的,就是用三维:i,j,k分别表示当前是哪一位,j代表元音(0)和辅音(1),k代表,到i位为止,j个单词的连续的个数。
这样dp方程就可以推出来了:
dp[i][0][1]=sum(dp【i-1】【1】【1】~dp【i-1】【1】【B】)*5
dp[i][1][1]=sum(dp【i-1】【0】【1】~dp[i-1][0][A])*21
dp【i】【0】【2】=dp【i-1】【0】【1】*5;
dp[i][0][3]=dp[i-1][0][2]*5 等等
同理,辅音也是:
dp【i】【1】【2】=dp【i-1】【1】【1】*21;
dp[i][1][3]=dp[i-1][1][2]*21 等等。
注意:初始化memset超时。改成循环。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000000+7;
typedef long long LL;
LL dp[5100][60][60];
int main()
{
int t,N,A,B;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&N,&A,&B);
/// memset(dp,0,sizeof(dp));
for(int i=0;i<=N;i++)
for(int j=0;j<=52;j++)
dp[i][0][j]=dp[i][1][j]=0;///j是当前字母连续的个数
dp[1][0][1]=5;///0元音
dp[1][1][1]=21;///1辅音
for(int k=2;k<=A;k++){
dp[1][0][k]=0;
}
for(int k=2;k<=B;k++){
dp[1][1][k]=0;
}
for(int i=2;i<=N;i++)
{
for(int j=1;j<=B;j++){
dp[i][0][1]+=dp[i-1][1][j]*5%mod;
dp[i][0][1]=dp[i][0][1]%mod;
}
for(int j=1;j<=A;j++){
dp[i][1][1]+=dp[i-1][0][j]*21%mod;
dp[i][1][1]=dp[i][1][1]%mod;
}
for(int j=2;j<=A;j++){
dp[i][0][j]=dp[i-1][0][j-1]*5%mod;
dp[i][0][j]%=mod;
}
for(int j=2;j<=B;j++){
dp[i][1][j]=dp[i-1][1][j-1]*21%mod;
dp[i][1][j]%=mod;
}
}
LL ans=0;
for(int i=1;i<=N;i++){
for(int k=1;k<=A;k++){
ans=(ans+dp[i][0][k])%mod;
}
}
for(int i=1;i<=N;i++){
for(int k=1;k<=B;k++){
ans=(ans+dp[i][1][k])%mod;
}
}
printf("%lld\n",ans);
}
return 0;
}