Loading

【题解】「AGC013D」Piling Up

传送门

题目大意:

开始有 \(n\) 个黑白球在袋子中,但是不知道具体多少黑球白球,有 \(m\) 次操作,每次从袋子中先拿一个球,再放入一个黑球一个白球,再拿走一个球,求所有初始情况下不同的拿出球的颜色序列的个数,模 \(10^9+7\)

\(n, m\le 3000\)

题解:

联考的 \(T1\)这tmd是CSP模拟,赛时发现是 \(3000+\) 就直接润了,赛后发现好像不难。

可以发现总是有 \(n\) 个球未被拿走的,设 \(f_{i, j}\) 表示操作了 \(i\) 次,袋中剩下 \(j\) 个黑球。

初值直接 \(f_{0,0\sim n} = 1\),直接 \(dp\)

然后你发现这样 \(dp\) 会算重,所以我们随机调题需要钦定一种方案最少要有一个时刻袋中没有黑球,这样就不会算重了。

我们也可以计算 \(solve (n, m) - solve (n-1, m)\) 的值,这个与上面等效,即黑球数 \(\ge 0\) 的方案数 \(-\) 黑球数 \(\ge 1\) 的方案数,这个也就是至少一次黑球数 \(= 0\) 的方案数。

Code
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i=j; i<=k; ++i)
#define ROF(i,j,k) for(int i=j; i>=k; --i)
inline int read (void) {
  int x = 0, f = 1, ch = getchar();
  while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
  while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
  return x * f;
}
const int maxn = 3005;
const int p = 1000000007;
int f[maxn][maxn];
inline void inc (int &x, int y) { (x += y) >= p ? x -= p : x; }
inline int solve (int n, int m) {
  if(n < 0) return 0;
  memset(f, 0, sizeof(f));
  FOR(i,0,n) f[0][i] = 1;
  FOR(i,0,m-1) FOR(j,0,n) {
    if(j) {
      inc (f[i+1][j-1], f[i][j]);
      inc (f[i+1][j], f[i][j]);
    }
    if(j != n) {
      inc (f[i+1][j], f[i][j]);
      inc (f[i+1][j+1], f[i][j]);
    }
  }
  int ans = 0;
  FOR(i,0,n) inc (ans, f[m][i]);
  return ans;
}
int main (void) {
  int n = read(), m = read();
  int ans = (solve (n, m) - solve (n-1, m) + p) % p;
  printf("%d\n", ans);
  return 0;
}
posted @ 2022-10-05 23:04  静谧时空  阅读(77)  评论(0)    收藏  举报