总共有 n n n 个人,编号 1 ∼ n 1\sim n 1∼n,三个种类 A , B , C A,B,C A,B,C,要求有连续不少于 m m m 个 A A A 种类的人,连续不多于 k k k 个 B B B 种类的人,问这 n n n 个人的有多少种组合方式?
思路参考 https://blog.csdn.net/wust_ZJX/article/details/46809951
难以处理至少问题,因此要把至少转换成至多,设事件 D = { D=\{ D={ 至多 n n n 个 A A A,至多 k k k 个 B B B } \} },事件 E = { E=\{ E={ 至多 m − 1 m-1 m−1 个 A A A,至多 k k k 个 B B B } \} },则 D − E = { D-E=\{ D−E={ 至少 m m m 个 A A A,至多 k k k 个 B } B\ \} B },即为最终答案。现在考虑至多 u u u 个 A A A,至多 v v v 个 B B B,令 d p [ i ] [ 0 ] , d p [ i ] [ 1 ] , d p [ i ] [ 2 ] dp[i][0],dp[i][1],dp[i][2] dp[i][0],dp[i][1],dp[i][2] 分别表示位置 i i i 放种类 A , B , C A,B,C A,B,C 对应的组合数,令 s u m = d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] + d p [ i − 1 ] [ 2 ] sum=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], 则对于种类 A A A 而言:
(1) i ≤ u i\le u i≤u 时,仍在限制之内:
d p [ i ] [ 0 ] = s u m dp[i][0]=sum dp[i][0]=sum
(2) i = u + 1 i=u+1 i=u+1 时,要减去 1 ∼ u 1\sim u 1∼u 这一段为 A A A 类对应的组合数,有一种:
d p [ i ] [ 0 ] = s u m − 1 dp[i][0]=sum-1 dp[i][0]=sum−1
(3) i > u + 1 i>u+1 i>u+1 时,则要减去 i − u ∼ i − 1 i-u\sim i-1 i−u∼i−1 这一段为 A A A 类对应的组合数:
d p [ i ] [ 0 ] = s u m − d p [ i − u − 1 ] [ 1 ] − d p [ i − u − 1 ] [ 2 ] dp[i][0]=sum-dp[i-u-1][1]-dp[i-u-1][2] dp[i][0]=sum−dp[i−u−1][1]−dp[i−u−1][2]
对于种类 B B B 同理有:
(1) i ≤ v i\le v i≤v 时,仍在限制之内:
d p [ i ] [ 1 ] = s u m dp[i][1]=sum dp[i][1]=sum
(2) i = v + 1 i=v+1 i=v+1 时,要减去 1 ∼ v 1\sim v 1∼v 这一段为 B B B 类对应的组合数,有一种:
d p [ i ] [ 1 ] = s u m − 1 dp[i][1]=sum-1 dp[i][1]=sum−1
(3) i > v + 1 i>v+1 i>v+1 时,则要减去 i − v ∼ i − 1 i-v\sim i-1 i−v∼i−1 这一段为 B B B 类对应的组合数:
d p [ i ] [ 1 ] = s u m − d p [ i − v − 1 ] [ 0 ] − d p [ i − v − 1 ] [ 2 ] dp[i][1]=sum-dp[i-v-1][0]-dp[i-v-1][2] dp[i][1]=sum−dp[i−v−1][0]−dp[i−v−1][2]
由于 C C C 类不影响限制条件,因此有:
d p [ i ] [ 2 ] = s u m dp[i][2]=sum dp[i][2]=sum
代码如下:
#include<iostream>
#include<cstdio>
//#define WINE
#define MOD 1000000007
#define MAXN 1000005
using namespace std;
typedef long long ll;
ll n,m,k,dp[MAXN][3],sum;
ll f(ll u,ll v){
dp[0][0]=dp[0][1]=0;dp[0][2]=1;
for(int i=1;i<=n;i++){
sum=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%MOD;
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)%MOD;
if(i<=v)dp[i][1]=sum;
else if(i==v+1)dp[i][1]=(sum-1+MOD)%MOD;
else dp[i][1]=((sum-dp[i-v-1][0]-dp[i-v-1][2])%MOD+MOD)%MOD;
dp[i][2]=sum;
}
return (dp[n][0]+dp[n][1]+dp[n][2])%MOD;
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF)
printf("%lld\n",((f(n,k)-f(m-1,k))%MOD+MOD)%MOD);
return 0;
}