【组合数学】AGC036C - GP 2

找性质的能力不行

Problem Statement

We have a sequence of $N$ integers: $x=(x_0,x_1,\cdots,x_{N−1})$. Initially, $x_i=0$ for each $i (0≤i≤N−1)$.

Snuke will perform the following operation exactly $M$ times:

Choose two distinct indices $i,j (0≤i,j≤N−1, i≠j)$. Then, replace $x_i$ with $x_i+2$ and $x_j$ with $x_j+1$.
Find the number of different sequences that can result after $M$ operations. Since it can be enormous, compute the count modulo $998244353$.

Constraints

  • $2≤N≤10^6$
  • $1≤M≤5×10^5$
  • All values in input are integers.

题目分析

这类题的一般套路是把一些奇奇怪怪的操作转化成局部量守恒;或者是操作对一些特殊量的影响有什么限制。

这里首先能够看出限制一:$\forall a_i \le 2m$.

再来考察一下操作有什么特性:在两个位置$i,j$分别加上$2,1$也就是把$j$的奇偶性翻转;$i$的奇偶性不影响。初始每个位置都为偶。这说明全部操作只有$m$次翻转奇偶性的机会,由此得到限制二:$\sum\limits [x_i为奇数]\le m$.

这两个限制的必要性上面已经论述了,充分性可以通过对$m$归纳得到。

现在问题变成了:

给定$n,m$,求长度为$n$的可空数列$\{x_i\}$满足$[\sum x_i=3m ]\and [\forall x_i \le 2m ]\and [\sum\limits [x_i为奇数]\le m]$的个数。

第一条限制很好处理,问题主要是第二条限制。

首先来考虑单纯满足第二条限制的数列个数,不妨记$f(n,m,k)$表示把$m$分为$n$组非空、且奇数个数$\le k$的方案数。那么这里有$f(n,3m,m)=\sum\limits _{p=1,p≡3m\pmod 2}^n {\frac{3m-p}{2}+n-1\choose n-1}{n \choose p}$,其中$p$是枚举的奇数个数。

容斥地考虑,现在要计算的另一部分问题应是$[\exists x_i > 2m ]\and [\sum\limits [x_i为奇数]\le m]$,也即:枚举最大数位置$pos$,把$m$分为$n$组非空、奇数个数$\le k$、且$x_{pos}$非空的方案数。

这里的“某一位置非空”就是很经典的问题了,可以先用$m-1$构造非空数列、再将$1$加到$x_{pos}$上;也可以再容斥一次,用$m$构造$n$的方案减去用$m$构造$n-1$的方案,意即此位置为零不占用$m$.

 1 #include<bits/stdc++.h>
 2 #define MO 998244353
 3 typedef long long ll;
 4 const int maxn = 3000000;
 5 
 6 ll n,m,ans;
 7 ll inv[maxn],fac[maxn];
 8 
 9 ll C(ll n, ll m)
10 {
11     if (n < m) return 0;
12     return fac[n]*inv[m]%MO*inv[n-m]%MO;
13 }
14 ll f(ll n, ll m, ll k)
15 {
16     ll ret = 0;
17     for (ll p=0; p<=k; p++)
18         if (((m-p)&1)==0){
19             ret = (ret+C((m-p)/2ll+n-1, n-1)*C(n, p)%MO)%MO;
20         }
21     return ret;
22 }
23 int main()
24 {27     scanf("%lld%lld",&n,&m);
28     fac[0] = inv[0] = inv[1] = 1;
29     for (int i=2; i<=n+3*m; i++)
30         inv[i] = (MO-1ll*MO/i*inv[MO%i]%MO);
31     for (int i=1; i<=n+3*m; i++)
32         inv[i] = inv[i-1]*inv[i]%MO, fac[i] = fac[i-1]*i%MO;
33 //    ans = (f(n, 3*m, m)-n*(f(n, m, m)-f(n-1, m, m))%MO+MO)%MO;
34     ans = (f(n, 3*m, m)-n*(f(n, m-1, m))%MO+MO)%MO;
35     printf("%lld\n",ans);
36     return 0;
37 }

 

END

posted @ 2019-11-03 18:18  AntiQuality  阅读(238)  评论(0编辑  收藏  举报