1. 程式人生 > 實用技巧 >P2592 [ZJOI2008]生日聚會

P2592 [ZJOI2008]生日聚會

容易發現已經結束掉的一個子串只要合法就對後面沒有影響,所以可以令 \(f_{i,j,p,q}\) 表示前 \(i+j\) 個人有 \(i\) 個男孩,\(j\) 個女孩,所有字尾中男孩最多比女孩多 \(p\) 個,女孩最多比男孩多 \(q\) 個的方案數。

轉移即列舉下一個位置是男孩或者女孩,記得對 \(0\)\(\max\)

時間複雜度 \(O(nmk^2)\)~

code:

#include<bits/stdc++.h>
using namespace std;
#define N 25
#define NN 155
#define Mod 12345678
#define Max(x,y)((x)>(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
int f[NN][NN][N][N];
int main()
{
    int n,m,k,ans=0,i,j,p,q;
    cin>>n>>m>>k;
    f[0][0][0][0]=1;
    For(i,0,n)
    For(j,0,m)
    For(p,0,k)
    For(q,0,k)
    {
        if(p<k)f[i+1][j][p+1][Max(q-1,0)]=(f[i+1][j][p+1][Max(q-1,0)]+f[i][j][p][q])%Mod;
        if(q<k)f[i][j+1][Max(p-1,0)][q+1]=(f[i][j+1][Max(p-1,0)][q+1]+f[i][j][p][q])%Mod;
    }
    For(p,0,k)
    For(q,0,k)ans=(ans+f[n][m][p][q])%Mod;
    cout<<ans;
    return 0;
}