题目大意
一共有N个人,编号为 (1...N)
题目要求给每一个人都要有一个属性,分别为 (R,P,G)
并且对于这些属性的人有一定的要求:
1.属性为 (G) 的人至少连续有 (m) 个
2.最多有连续 (k) 个为 (R) 属性的人
问符合这种要求的排列有多少个
大致思路:
这个题比较麻烦的是有两个条件,一个最多、一个最少。所以我们需要尽量把这两个条件变成一个条件。
我们可以求出 (G) 最多长度为 (n) ,(R) 最多长度为 (k) 时的情况数,减去
(G) 最多长度为 (m-1) ,(R) 最多长度为 (k) 时的情况数。
相减结果就是答案。
所以我们考虑一个 (DP[i][0...2]) 表示第 (i) 个人为 (R,P,G) 时的情况。
下面以 (G) 来考虑 (DP) 式子的转移公式:
设 (G) 最多长度为 (u) 时:
当 (i<=u) 很明显,不存在非法的情况,所以状态直接可以进行转移:(dp[i][0] = dp[i-1][0]+dp[i-1][1]+dp[i-1][2])
(下面为了方便将 (sum= dp[i-1][0]+dp[i-1][1]+dp[i-1][2]) )
当 (i = u+1) 时,存在一种情况非法:即从 (1...i) 都是 (G) 。所以:
$dp[i][0] = sum-1 $
当 (i>u+1) 时。存在非法情况为:(G) 长度为 (u+1)
这个非法情况的前提是:第 (i-u) 位是 (G)
第 (i-u) 位是 (G) 的前提是: 第 (i-u-1) 位不是 (G)
第 (i-u-1) 位不是 (G) ,那么肯定就是其他的两种情况。所以我们得出式子:
$ dp[i][0] = sum - dp[i-u-1][1]-dp[i-u-1][2] $
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
const int mod=1e9+7;
ll dp[maxn][3];
int n,m,k;
inline ll slove(int u,int k)
{
dp[0][0]=1;
dp[0][2]=dp[0][1]=0;//什么都不放的时候,整体方案数为1
for(int i=1;i<=n;++i){
ll sum=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2]+mod)%mod;
dp[i][2]=sum;
if(i<=u)
dp[i][0]=sum;
else if(i==u+1)
dp[i][0]=(sum-1+mod)%mod;
else
dp[i][0]=(sum-dp[i-u-1][1]-dp[i-u-1][2]+mod)%mod;
if(i<=k)
dp[i][1]=sum;
else if(i==k+1)
dp[i][1]=(sum-1+mod)%mod;
else
dp[i][1]=(sum-dp[i-k-1][0]-dp[i-k-1][2]+mod)%mod;
//cout<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][2]<<endl;
}
return (dp[n][0]+dp[n][1]+dp[n][2]+mod)%mod;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m>>k)
{
cout<<((slove(n,k)-slove(m-1,k))%mod+mod)%mod<<endl;
}
return 0;
}