D. Caesar‘s Legions(经典计数dp)

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;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/113094177