1. 程式人生 > >BZOJ1037 [ZJOI2008]生日聚會Party

BZOJ1037 [ZJOI2008]生日聚會Party

dad using 整數 。。 一行 logs 是否 後綴 input

Description

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

Input

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

Output

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

Sample Input

1 2 1

Sample Output

1

HINT

n , m ≤ 150,k ≤ 20。

題解

第一眼看過去認為這是數學題。。。不過不會推結論。。。

從dp的角度入手吧。。。

我們設$f_{i,j,a,b}$為$i$個男孩,$j$個女孩排成一排,滿足題目的條件且任意後綴的男孩數至多比女孩數多$a$個,至多比女孩少$b$個的方案數,那麽顯然,答案為$f_{n,m,k,k}$。

邊界:$f_{0,0,a,b}=1$;

遞推式:兩種選擇,最後一個放男孩和最後一個放女孩。若放男孩,那除他之外末尾的男孩可以比女孩多$a-1$個,少$min(b+1,k)$個,女孩同理。即:

$$f_{i,j,a,b}=f_{i-1,j,a-1,min(b+1,k)}+f_{i,j-1,min(a+1,k),b-1}$$

dp時按$i+j$遞增序(不過好像沒有必要,直接枚舉$i,j$分別遞增就行)。

復雜度$O(nmk^2)$。

附代碼:

#include <algorithm>
#include <cstdio>
using std::min;
using std::max;
const int N = 155;
const int K = 25;
const int mod = 12345678;
int f[N][N][K][K];
int main() {
  int n, m, k;
  scanf("%d%d%d", &n, &m, &k);
  for (int i = 0; i <= k; ++i)
    for (int j = 0; j <= k; ++j)
      f[0][0][i][j] = 1;
  for (int ij = 1; ij <= n + m; ++ij)
    for (int i = max(ij - m, 0); i <= min(ij, n); ++i) {
      int j = ij - i;
      for (int a = 0; a <= k; ++a)
        for (int b = 0; b <= k; ++b) {
          f[i][j][a][b] = 0;
          if (i && a) f[i][j][a][b] += f[i - 1][j][a - 1][min(b + 1, k)];
          if (j && b) f[i][j][a][b] += f[i][j - 1][min(a + 1, k)][b - 1];
          f[i][j][a][b] %= mod;
        }
    }
  printf("%d\n", f[n][m][k][k]);
  return 0;
}

  

BZOJ1037 [ZJOI2008]生日聚會Party