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