题意:构建一个由G、R、P三个字母构成的字符串,要求出现G则必须要大于等于连续M个,出现R则必须要小于等于连续K个
脑子太笨了,不会转化,一开始无从下手,对至少M个无法处理,想着可以从之前i-m之前都转移过来。还是看了题解。
将原题转化为(至多n个G,至多k个R) - (至多m-1个G,至多k个R)。真他妈巧妙啊= =。
dp[i][0] 第i个为G,至多有u个G 和v个R的个数
dp[i][1] 第i个为R,至多有u个G 和v个R的个数
dp[i][2] 第i个为P,至多有u个G 和v个R的个数
对于i<=u的时候,怎么放都行
dp[i][0] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2]
i == u+1 的时候 多了一种全是G的情况
dp[i][0] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2] - 1
i > u+1的时候 我们需要计算之前多的情况,即已经连续u个G了。那么就是找到一个状态是满足i-1到i-u已经连续u个G的,就是dp[i-u-1][1] 和 dp[i-u-1][2]
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;
const int maxn = 1e6 + 5;
typedef long long LL;
//dp[i][0] 第i个为G,至多有u个G 和v个R的个数
//dp[i][1] 第i个为R,至多有u个G 和v个R的个数
//dp[i][2] 第i个为P,至多有u个G 和v个R的个数
LL dp[maxn][3];
int n,m,k;
LL solve(int u, int v){
for(int i=1; i<=n; i++){
LL sum = dp[i-1][0] + dp[i-1][1] + dp[i-1][2];
if(i == 1) sum = 1;
dp[i][2] = sum;
if(i <= u){
dp[i][0] = sum % mod;
dp[i][0] %= mod;
}
else if(i == u+1){
dp[i][0] = (sum - 1) % mod;;
dp[i][0] %= mod;
}
else{
dp[i][0] = (sum - dp[i-u-1][1] - dp[i-u-1][2]) % mod;
dp[i][0] %= mod;
}
if(i <= v){
dp[i][1] = sum % mod;
dp[i][1] %= mod;
}
else if(i == v+1){
dp[i][1] = (sum - 1) % mod;;
dp[i][1] %= mod;
}
else{
dp[i][1] = (sum - dp[i-v-1][0] - dp[i-v-1][2]) % mod;
dp[i][1] %= mod;
}
}
return (dp[n][0] + dp[n][1] + dp[n][2]) % mod;
}
int main(){
while(scanf("%d%d%d",&n,&m,&k) == 3 && n){
printf("%lld\n",((solve(n,k) - solve(m-1,k)) % mod + mod) % mod);
}
}