AGC036C GP 2
有个一开始全\(0\)的数组,每次选择两个不同的位置,分别\(+1\)和\(+2\)。
问操作恰好\(m\)次之后可能形成的不同的数组的方案数。
\(n\le 10^6,m\le 5*10^5\)
考虑最终形成的数组为\(a_i\)。如果能够将其表示成\(x_i+2y_i\),那么有:\(\sum x_i=\sum y_i=m\)。
分析怎样的\((x_i,y_i)\)有解:相当于每次选择\(i\neq j\),使得\(x_i,y_j\)各减一,最终能都减到\(0\)。
显然的必要条件:\(x_i\le \sum_{j\neq i}y_j=m-y_i\)。于是有\(x_i+y_i\le m\)。可证这也是充分条件:
忽略所有\(x_i=y_i=0\)的点。
边界情况:\(n=2\)。此时\(x_1+y_1=x_2+y_2=m\),因为\(x_1+x_2=y_1+y_2=m\),可以推出\(x_1=y_2,x_2=y_1\),有解。
找到个\(x_i+y_i\)最大的,对于\(x_i,y_i\)中的较大者,找到\(y_j\)或\(x_j\)(\(j\neq i\)),两者各减一。(一定能找到:不妨设\(x_i\ge y_i\),如果找不到\(y_j>0\),则\(y_i=m\),此时\(x_i+y_i>m\))
因为\(x_i+y_i=m\)不超过两个(否则总和大于\(2m\)),所以搞完之后仍然满足\(x_i'+y_i'\le m'\)。
归纳得证。
接下来问题是对于\(a_i\)找到合适的\(y_i\)。首先有\(\sum a_i=3m\),然后关于\(y_i\)的条件:
- \(\sum y_i=m\)
- \(a_i-2y_i+y_i\le m\)
- \(2y_i\le a_i\)
可得\(\max(a_i-m,0)\le y_i\le \lfloor\frac{a_i}{2}\rfloor\)。然后得到\(\sum y_i\)的上下界,从而\(\sum \max(a_i-m,0)\le m\le \sum\lfloor\frac{a_i}{2}\rfloor\)。
整理得\(\sum a_i=3m,\sum (a_i\mod 2)\le m,\sum \max(a_i-m,0)\le m\),充分必要。
继续分析:当满足\(\sum a_i=3m\)时,找到最大值次大值\(fir,sec\),那么第三条限制即\(\max(fir-m,0)+\max(sec-m,0)\le m\),将\(\max\)拆开,发现其等价于\(fir\le 2m\)。所以把第三个条件换成\(\max a_i\le 2m\)。
然后就可以计数啦。列出式子:
经过简单的推式子过程,就可以得到\(O(n+m)\)的做法。
using namespace std;
#include <bits/stdc++.h>
#define N 1000005
#define mo 998244353
#define ll long long
ll qpow(ll x,ll y=mo-2){
ll r=1;
for (;y;y>>=1,x=x*x%mo)
if (y&1)
r=r*x%mo;
return r;
}
int n,m;
ll fac[N*3],ifac[N*3];
void initC(int n){
fac[0]=1;
for (int i=1;i<=n;++i)
fac[i]=fac[i-1]*i%mo;
ifac[n]=qpow(fac[n]);
for (int i=n-1;i>=0;--i)
ifac[i]=ifac[i+1]*(i+1)%mo;
}
ll C(int m,int n){
if (m<n) return 0;
return fac[m]*ifac[n]%mo*ifac[m-n]%mo;
}
ll calc(int n,int k){
if (k&1) return 0;
k>>=1;
return (C(k+n-1,n-1)-n*C(k-(m+1)+n-1,n-1))%mo;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
initC(n+m*3/2);
ll ans=0;
for (int j=0;j<=min(n,m);++j)
ans=(ans+C(n,j)*(calc(n,3*m-j)-calc(n-1,m-j)*j%mo))%mo;
ans=(ans+mo)%mo;
printf("%lld\n",ans);
return 0;
}