ZOJ 3747
题意:有n个字母(只含A、B、C),求至少有m个连续的A,最多有k个连续的C的排列种数。
输入:n,m,k
输出:排列的种数
题意非常的简单,但是。。。
我们考虑问题的另一种表达:至多k个连续C,至多n个连续A情况减去至多k个连续C,至多(m-1)个连续A 情况。
//dp[i][0]表示第i个为A,至多有u个连续A,至多有v个连续C的个数 //这里的u和v固定
//dp[i][1]表示第i个为B,至多有u个连续A,至多有v个连续C的个数 //这里的u和v固定
//dp[i][2]表示第i个为C,至多有u个连续A,至多有v个连续C的个数 //这里的u和v固定
当第i个为B时不会对A C的连续产生影响:
dp[i][2]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2];
当第i个为A时
i<u 绝对不会超过u个连续这个限制条件
所以dp[i][0]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2];
如果i=u+1时,要排除前u个都放了G的情况,dp[i][0]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2]-1;
这里为什么要单独分类讨论呢,因为i=u+1时,i-u-1等于0,出现bug.
如果i>u+1时,要排除从i-1到i-u位置都放了G的情况,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];
当第i个为C时,同上。
n=1,2,3......时如下图
当i=u+1时
比如:假设i=3,不能超过2个,如果要找前两个连续G的情况,只要前两个不是两个G都可以!!!只有一种情况!!!
当i>u+1时
比如:假设i=4,不能超过2个,要找2到3位置都有G的情况,只有1位置可以放三种,所以由1位置决定。就找dp[4-2-1][1]和dp[4-2-1][2],即把连续断开!!!

#include<bits/stdc++.h>
#define ll long long
#define M 1000000007
using namespace std;
ll dp[1100000][5];
ll n,m,k,u,v;
ll solve()
{
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])%M;
dp[i][2]=sum;
if(i<=u)
dp[i][0]=sum;
else if (i==u+1)
dp[i][0]=(sum-1)%M;
else
dp[i][0]=(sum-dp[i-u-1][1]-dp[i-u-1][2])%M;
if(i<=v)
dp[i][1]=sum;
else if (i==v+1)
dp[i][1]=(sum-1)%M;
else
dp[i][1]=(sum-dp[i-v-1][0]-dp[i-v-1][2])%M;
}
return (dp[n][0]+dp[n][1]+dp[n][2])%M;
}
int main()
{
while(~scanf("%lld%lld%lld",&n,&m,&k))
{
u=n,v=k;
ll ans=solve();
u=m-1,v=k;
ans=((ans-solve())%M+M)%M;
printf("%lld\n",ans);
}
return 0;
}
uva 10328
显然n张牌总的排列数为2^n,如果减去最多有(k-1)张连续正面的情况,就是最后的结果。
dp[i][0]:表示第i张牌为正面,且最多有k张连续的正面的种数
dp[i][1]=dp[i-1][0]+dp[i-1][1];
dp[i][0] 当i<=k时,dp[i][0]=dp[i-1][0]+dp[i-1][1]
当i==k+1时,dp[i][0]=dp[i-1][0]+dp[i-1][1]-1;
当i>k+1时,dp[i][0]=dp[i-1][0]+dp[i-1][1]-dp[i-k-1][1];
思路同上题
详解
本文详细解析了ZOJ3747题目的算法实现过程,通过动态规划方法解决字母排列计数问题,区分不同条件下排列数量的计算,并提供了完整的代码示例。

495

被折叠的 条评论
为什么被折叠?



