https://codeforces.com/problemset/problem/118/D
大佬讲的很好辣
Codeforces 118D Caesar's Legions【dp】好题
题目大意:
有n1个数字1,有n2个数字2(看的Note翻译的,不知道原文是不是也是这样)
将n1+n2个数字排成一排,其中要求连续的数字1最多可以有k1个,连续的数字2最多有k2个。
问一共有多少种分配方案。
思路:
1、统计计数问题,考虑dp。
设定dp【i】【j1】【j2】【k1】【k2】【l(2)】,表示dp到第i位,当前数字类型是l,其中数字1使用了j1个,数字2使用了j2个,并且最后一个数字(当前数字)之前的连续l(假设是0)一共有k1个,再之前连续的另外一种数字一共有k2个的方案数。明显能够包含住所有的情况,因为内存限制包括时间限制,我们考虑将这个数组降低维度。
我们其实只考虑当前数字的情况即可,那么:
设定dp【i】【j】【k】【l(2)】,表示当前dp到第i位,当前数字类型是l,对应当前数字l已经使用了j个,并且最后一个数字(当前数字)之前连续的l一共有k个的方案数。
2、设定好dp数组之后,考虑递推出其状态转移方程(此时我们l==0表示上边添加的数字为1,l==1表示上边天剑的数字为2):
if(k==1)
dp【i】【j】【k】【0】+=dp【i-1】【i-j】【kk】【1】;
表示我们当前第i位子上的数和第i-1位子上的数不同,那么对应我们需要考虑上一位子的状态,首先我们知道,在第i-1位子上的时候,一共有数字i-1个,对应其中一定包含j-1个数字1,那么其包含数字2的个数为:i-1-(j-1)=i-j;那么此时我们需要再枚举这样一个变量:因为我们此时第i-1位子上的数字要是2,那么我们需要知道此时连续的2的个数。那么我们再枚举一个kk即可。
if(k>1)
dp【i】【j】【k】【0】+=dp【i-1】【j-1】【k-1】【0】;
表示我们当前第i位子上的数和第i-1位子上的数相同,那么对应我们上一位子的状态:dp到第i-1位,已经使用数字1的个数为j-1个,对应连续的数字1的个数为k-1.直接累加上即可。
同理,对应有:
if(k==1)
dp【i】【j】【k】【1】+=dp【i-1】【i-j】【kk】【0】;
if(k>1)
dp【i】【j】【k】【1】+=dp【i-1】【j-1】【k-1】【1】;
3、注意对1e8取模,注意初始化,其他的就没有什么了。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=210;
typedef int LL;
LL dp[maxn][maxn][maxn][3];
const LL mod=1e8;
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n1,n2,k1,k2;cin>>n1>>n2>>k1>>k2;
dp[1][1][1][1]=1;
dp[1][1][1][2]=1;
for(LL i=2;i<=n1+n2;i++){
///当前数字类型为1时
for(LL j=1;j<=i&&j<=n1;j++){
for(LL k=1;k<=k1;k++){
if(k==1){
for(LL kk=1;kk<=k2;kk++){
dp[i][j][k][1]+=dp[i-1][i-j][kk][2];
dp[i][j][k][1]%=mod;
}
}
else{
dp[i][j][k][1]+=dp[i-1][j-1][k-1][1];
dp[i][j][k][1]%=mod;
}
}
}
///当前数字类型为2时
for(LL j=1;j<=i&&j<=n2;j++){
for(LL k=1;k<=k2;k++){
if(k==1){
for(LL kk=1;kk<=k1;kk++){
dp[i][j][k][2]+=dp[i-1][i-j][kk][1];
dp[i][j][k][2]%=mod;
}
}
else{
dp[i][j][k][2]+=dp[i-1][j-1][k-1][2];
dp[i][j][k][2]%=mod;
}
}
}
}
LL ans=0;
for(LL i=1;i<=k1;i++){
ans=(ans%mod+dp[n1+n2][n1][i][1]%mod)%mod;
}
for(LL i=1;i<=k2;i++){
ans=(ans%mod+dp[n1+n2][n2][i][2]%mod)%mod;
}
cout<<ans<<endl;
return 0;
}