UVa 580 Critical Mass (递推 & 计数原理)

题目

题目大意

有一些装有铀(用\(U\)表示)和铅(用\(L\)表示)的盒子, 数量均足够多。要求把\(n\)(\(n ≤ 30\))个盒子放成一行, 但至少有\(3\)\(U\)放在一起, 有多少种放法? 例如, \(n = 4, 5, 30\)时答案分别为\(3, 8\)\(974791728\)

题解

设答案为\(f(n)\), 根据\(3\)\(U\)的位置分类。假定是\(i\), \(i + 1\), \(i + 2\)这三个盒子, 则前\(i - 1\)个盒子不能有\(3\)\(U\)放在一起, 而\(i - 2\)\(i - 1\)仍然有可能与\(i\)\(i + 1\)组成\(3\)\(U\), 因此保证\(i - 1\)\(L\)。设\(n\)个盒子没有\(3\)\(U\)放在一起的方案数为\(g(n) = 2^n-f(n)\), 则前\(i - 2\)个盒子的方案有\(g(i - 2)\)种。根据加法原理和乘法原理, 得到\(f(n) = 2^{n - 3} + \Sigma_{i = 2}^{n - 2}g(i - 2)2^{n - i - 2}\)

代码

#include <cstdio>
long long f[40], g[40] = {1, 2, 4};
int n;
int main(int argc, char const *argv[]) {
  for (register int i(3); i <= 30; ++i) {
    f[i] = 1 << (i - 3);
    for (register int j(2); j < i - 1; ++j) {
      f[i] += g[j - 2] * (1 << (i - j - 2));
    }
    g[i] = (1 << i) - f[i];
  }
  while (~scanf("%d", &n) && n) {
    printf("%lld\n", f[n]);
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/forth/p/9720757.html