[清华集训2016] 你的生命已如风中残烛

简化题意

(w_i) 全部减 (1),则问题变成一个序列,其中给定有 (n) 个正数 (w_i),其余都是 (-1),和是 (0),前缀和均非负,求排列方案数。

做法

如果和是 (1),且要求前缀和全为正数,有结论:每个排列的所有循环移位只有 (1) 种合法,所以计数圆排列数即可,《具体数学》7.5 章有详细证明,其实就是每次必须要取最后一个最小值位置作为起点,使得其他最小值位置跨过序列结尾,前缀和为 (1),否则如果有两个相等最小值而取前一个作为起点,第二个最小值位置前缀和是 (0)

本题前缀和可以为 (0),因此每个最小值都能取,分析失效。

证 Catalan 数时,可以在开头放个 (1),但本题中有多种不等价的正数,这种做法是无效的。

在结尾放个 (-1),问题变成前 (m) 个元素前缀和非负,且总和为 (-1)

类似地,所有循环移位中现在只能取第一个最小值位置作为起点了,否则跨过序列结尾,之前的最小值位置前缀和会变成 (-1)

(m+1) 个点共有 (m!) 种圆排列,而序列中有 (m - n + 1)等价(-1) 只能取额外放置的 (1) 个放在结尾(结尾一定是 (-1)),因此答案 (displaystylefrac{m!}{m - n + 1})

P.S. 对于第一个结论,如果和为 (s),那么有 (s) 种循环移位。

#include <cstdio>

int main() {
  int n, m = 0, s = 1, x;
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    scanf("%d", &x);
    m += x;
  }
  for (int i = 2, li = m - n; i <= li; ++i)
    s = 1LL * s * i % 998244353;
  for (int i = m - n + 2; i <= m; ++i)
    s = 1LL * s * i % 998244353;
  printf("%d
", s);
  return 0;
}
原文地址:https://www.cnblogs.com/RiverHamster/p/sol-lg6672.html