标签:ace c++ 其他 std 存在 ++ 长度 math ==
一共有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;
}
标签:ace c++ 其他 std 存在 ++ 长度 math ==
原文地址:https://www.cnblogs.com/SCaryon/p/9153263.html