【動態規劃】[BZOJ1037][ZJOI2008]生日聚會Party

題目描述

今天是hidadz小朋友的生日,她邀請了許多朋友來參加她的生日party。 hidadz帶着朋友們來到花園中,打算坐成一排玩遊戲。爲了遊戲不至於無聊,就座的方案應滿足如下條件:對於任意連續的一段,男孩與女孩的數目之差不超過k。很快,小朋友便找到了一種方案坐了下來開始遊戲。hidadz的好朋友Susie發現,這樣的就座方案其實是很多的,所以大家很快就找到了一種,那麼到底有多少種呢?熱愛數學的hidadz和她的朋友們開始思考這個問題…… 假設參加party的人中共有n個男孩與m個女孩,你是否能解答Susie和hidadz的疑問呢?由於這個數目可能很多,他們只想知道這個數目除以12345678的餘數。

僅包含一行共3個整數,分別爲男孩數目n, 女孩數目m, 常數k。

應包含一行,爲題中要求的答案。

樣例輸入

1 2 1

樣例輸出

1

題目解析

首先我們可以發現,我們如果定義狀態,至少要2維(總人數,女生)那麼經過觀察如果僅僅是2維的話,我們並不能找到(總人數+1, 女生)或者(總人數+1,女生+1)的狀態轉移,那麼我們多開一維表示當前從尾部開始的一直往前的每一個後綴子串中的差值最大是多少,但是由於每一次我們可以增加男生或者增加女生,我們並不能確定當男生增加(或者女生增加)時這個差值是+1或者-1所以我們再開一維表示分別表示男生比女生多和女生比男生多的數量。所以我們可得到

dp(i,j,k,p)
我們可以發現如果當前的男生+1那麼有
dp(i+1,j,k+1,p1)+=dp(i,j,k,p)
但是如果此時女生本來就一個都沒有那麼p本身就是0了那麼
dp(i+1,j,k+1,max{0,p1})+=dp(i,j,k,p)
同理有
dp(i+1,j+1,max{0,k1},p+1)+=dp(i,j,k,p)
本題就是這樣。。。

代碼

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 150;
const int MAXK = 20;
const int MOD = 12345678;
int dp1[MAXN+10][MAXK+2][MAXK+2], dp2[MAXN+10][MAXK+2][MAXK+2];
int main(){
    freopen("party.in", "r" , stdin);
    freopen("party.out", "w", stdout);
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    int sum = n + m;
    dp1[0][0][0] = 1;
    for(int i=0;i<sum;i++){
        swap(dp1, dp2);
        memset(dp1, 0, sizeof dp1);
        for(int j=0;j<=min(i, m);j++){
            for(int k1=0;k1<=k;k1++){
                for(int k2=0;k2<=k;k2++){
                    dp1[j+1][max(k1-1, 0)][k2+1] += dp2[j][k1][k2];
                    dp1[j][k1+1][max(k2-1, 0)] += dp2[j][k1][k2];
                    dp1[j][k1][k2] %= MOD;
                }
            }
        }
    }
    int ans = 0;
    for(int k1=0;k1<=k;k1++){
        for(int k2=0;k2<=k;k2++){
            ans = (ans + dp1[m][k1][k2]) % MOD;
        }
    }
    printf("%d\n", ans);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章