D.シーザーの軍団(クラシックカウントdp)

https://codeforces.com/problemset/problem/118/D


大きな男はそれがとても辛かったと言いました

Codeforces 118D Caesar'sLegions【dp】良い質問

本旨:

n1の数字1とn2の数字2があります(注の翻訳を参照してください。元のテキストが同じかどうかはわかりません)

n1 + n2桁を行に配置します。これには、連続する桁の場合は最大k1、連続する桁の場合は最大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】【ij】【kk】【1】;

これは、i番目の座席の現在の番号がi-1番目の座席の番号と異なることを意味するため、前の座席の状態を考慮する必要があります。まず、i-1番目の座席が当時、合計数i-1があり、それに対応してj-1数1が含まれている必要があり、数2を含む数は次のようになります。i-1-(j-1)= ij;次に、そのような数を列挙する必要があります。再び変数:i-1番目の位置の数が2の場合、この時点で連続する2の数を知る必要があるためです。次に、もう1つの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】【ij】【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