ZOJ - 3747 Attack on Titans [有条件限制的经典递推计数好题]
题目大意是 有n个士兵的排列,士兵有GRP三种类型,要求至少有m个G士兵连续,至多有k个R士兵连续,问有多少种方案,答案 取模1e9+7
题目分析
我们看到这个题目,很显然是一个计数的问题,那么如果从简单入手考虑,假设不存在上述条件,就是有n个士兵,每个士兵有三种类型,很显然就是 种情况,然后现在我们加上假设条件,根据尝试,我们发现至多有K个R士兵连续这种情况比较容易考虑,这是我们可以采用递推的思路,现在我用f(n)来表示到达第n个位置时满足上述限制条件的种类数,很显然,当n<=K时,限制条件不起作用,所以 ,当n=k+1时,只有一种情况:所有士兵全为R的时候的,是不满足条件的,此时我们只要删去这一种情况就可以了,即 。
当n逐渐增加的时候,由于前面已经不存在不满足条件的情况了,所以,我们只要考虑最后一个新增的为R时,是否会形成连续k+1个R,假设形成了,有多少种这样的情况呢,很显然就是 种啦,即,当 时,
但是我们现在有两个限制条件,并且至少有m个连续并不是很容易计算,此时,我们就会想到正难则反,我们通过计算至多有n个连续的G减去至多有m-1个连续的G的情况(连续人数的范围就控制在m-n之间)就会是我们要的至少有m个G连续。
再根据上面的方法 就能计算G的可能性。
由于现在我们有两个限制条件,三种士兵,所以我们不再简单的乘三,把各种情况都分离开来。用一个dp数组来记录种类数,dp[i][j] ,i表示当前序列种的第i个士兵,j代表士兵的种类。
0表示G,1表示P,2表示R;
现在我们的问题变成了 {至多n个连续的G,k个连续的R的个数} {至多m-1个连续的G,k个连续的R的个数}
那么怎么计算 至多u个连续G,v个连续R的种类数呢?
当 时 显然 dp[i][0]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%mod;
而当 时, dp[i][0]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-1)%mod;
时
dp[i][0]=((dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-dp[i-u-1][1]-dp[i-u-1][2])%mod+mod)%mod;
//因为在我们删去的情况中i-u到i-1这一段都成了G,所以第i-u-1个不可能G,所以我们只要减去第i-u-1个为P,R的两种情况就好了。
以此递推即可解决,对于dp数组的初始化,我们只要满足一开始能够计算出三个位置的值,所以在第0个无意义的位置, 给其中一个赋初值为1就好了
代码如下
#include <bits/stdc++.h>
#define cl(arr,val) memset(arr,val,sizeof(arr))
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll dp[1000005][4];
int n,m,k;
ll solve(int u,int v)
{
//cl(dp,0);
dp[0][2]=dp[0][0]=0;
dp[0][1]=1;
for(int i=1; i<=n; i++)
{
dp[i][1]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%mod;
if(i<=u)
{
dp[i][0]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%mod;
}
else if(i==u+1)
{
dp[i][0]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-1)%mod;
}
else
{
dp[i][0]=((dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-dp[i-u-1][1]-dp[i-u-1][2])%mod+mod)%mod;
}
if(i<=v)
{
dp[i][2]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%mod;
}
else if(i==v+1)
{
dp[i][2]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-1)%mod;
}
else
{
dp[i][2]=((dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-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()
{
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
printf("%lld\n",(solve(n,k)-solve(m-1,k)%mod+mod)%mod);
}
return 0;
}