题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5170
题意:有n个位置,填充G,P,R三个字母,问填充至少m个连续的G,至多k个连续的R的情况有多少种
分析:动态规划,dp[i][j](j = 0->G,j=1->P,j = 2->R)
dp[i][j]表示第i个数填充j对应的字母的时候,前i个数有至多不超过u个连续的G和v个连续的R
j=1时,填充i不影响之前的结果,dp[i][1] = dp[i-1][0] + dp[i - 1][1] + dp[i - 1][2],设结果为sum
j=0时,当i位置<=m时,之前最多有m-1个连续的G,不影响结果dp[i][0] = sum
i=m+1时,如果这m+1全为G就不符合题意,dp[i][0] = sum - 1
i > m + 1时,它前面的m个字母如果全为G,则再前面的字母无论为什么情况都不符合题意,但是不能为G,因为如果是G的话,连续的就超过m个了.dp[i][0] = sum - dp[i - m - 1][1] - dp[i - m - 1][2]
k同理
至少m个,至多k个就是至多n个,至少k个-至多m-1个,至少k个
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod = 1e9 + 7;
const int maxn = 1e6 + 10;
int n,m,k;
ll dp[maxn][3];//dp[i][j]表示前i个位置放l至多u个连续的R和至多v个连续的G的方案个数
ll work(int u,int v)
{
dp[0][0] = 1;
dp[0][1] = 0;
dp[0][2] = 0;
for(int i = 1; i <= n; i++)
{
ll sum = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2]) % mod;
dp[i][1] = sum;
if(i <= u)//i-1一定小于u,所以不存在可能为u+1长度的情况
{
dp[i][0] = sum;
}
else if(i == u + 1)//第i个位置放G,i的前u个位置也放G
{
dp[i][0] = (sum - 1) % mod;
}
else//第i个位置放G,它前面有连续u个数全为G,再前面的是啥都行,后面的由前面推过来,而且再前面只能是R或者P
{
dp[i][0] = ((sum - dp[i - u - 1][1] - dp[i - u - 1][2]) % mod + mod) % mod;
}
if(i <= v)//更新R和更新G类似
{
dp[i][2] = sum;
}
else if(i == v + 1)
{
dp[i][2] = (sum - 1) % mod;
}
else
{
//注意减法取模写法
dp[i][2] = ((sum - dp[i - v - 1][0] - dp[i - v - 1][1]) % mod + mod) % mod;
}
}
return (dp[n][0] + dp[n][1] + dp[n][2]) % mod;
}
int main()
{
//多组输入,memset超时
while(cin>>n>>m>>k)//至多n个G,k个R-至多m - 1个G,k个R
{
//memset(dp,0,sizeof(dp));
ll cnt1 = work(n,k);
//memset(dp,0,sizeof(dp));
ll cnt2 = work(m - 1,k);
ll res = ((cnt1 - cnt2) % mod + mod) % mod;
cout<<res<<endl;
}
return 0;
}