单位根反演好题。
提示:是照搬的 这篇题解 的做法,只是加了一点小小的解释。
首先,做等价变换:给第 i i i个位置加上 i − 1 i-1 i−1,问题转化为了求单调递增序列,即从 [ 0 , N + M − 1 ] [0,N+M-1] [0,N+M−1]中选 N N N个不同 的数,使得这些数模 mod \operatorname{mod} mod的值为 k k k。
这事实上是一个二元 G F GF GF的问题。先不考虑选 N N N个数的限制,记 n = N + M n=N+M n=N+M,写出答案的生成函数形式: ∏ i = 0 n − 1 ( 1 + x i ) \prod_{i=0}^{n-1}(1+x^i) ∏i=0n−1(1+xi)
记 k = mod k=\operatorname{mod} k=mod,那么我们要求所有 i k + r ik+r ik+r项的系数和,这通常可以用单位根反演来解决。
对于任意多项式 f ( x ) f(x) f(x),我们有:
∑ k ∣ i [ x i ] f ( x ) = ∑ i = 0 n − 1 [ x i ] f ( x ) 1 k ∑ j = 0 k − 1 w k i j = 1 k ∑ i = 0 n − 1 a i ∑ j = 0 k − 1 ( w k j ) i = 1 k ∑ j = 0 k − 1 ∑ i = 0 n − 1 a i ( w k j ) i = 1 k ∑ j = 0 k − 1 f ( w k j ) \begin{aligned}\sum_{k|i}[x^i]f(x)&=\sum_{i=0}^{n-1}[x^i]f(x)\frac{1}{k}\sum_{j=0}^{k-1}w_k^{ij}\\&=\frac{1}{k}\sum_{i=0}^{n-1}a_i\sum_{j=0}^{k-1}(w_k^j)^i\\&=\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^{n-1}a_i(w_k^j)^i\\&=\frac{1}{k}\sum_{j=0}^{k-1}f(w_k^j)\end{aligned} k∣i∑[xi]f(x)=i=0∑n−1[xi]f(x)k1j=0∑k−1wkij=k1i=0∑n−1aij=0∑k−1(wkj)i=k1j=0∑k−1i=0∑n−1ai(wkj)i=k1j=0∑k−1f(wkj)
类似的: ∑ [ x i k + r ] f ( x ) = 1 k ∑ j = 0 k − 1 w k − j r f ( w k j ) \sum[x^{ik+r}]f(x)=\frac{1}{k}\sum_{j=0}^{k-1}w_k^{-jr}f(w_k^j) ∑[xik+r]f(x)=k1∑j=0k−1wk−jrf(wkj)
注意这里的 k k k不是 2 2 2的次幂,因此不能直接计算。要想办法把单位根搞掉。
注意到 x n − 1 = ∏ i = 0 n − 1 ( x − w n i ) x^n-1=\prod_{i=0}^{n-1}(x-w_n^i) xn−1=∏i=0n−1(x−wni),令 x = − 1 x=-1 x=−1 ,那么 ∏ i = 0 n − 1 ( w n i + 1 ) = 1 − ( − 1 ) n \prod_{i=0}^{n-1}(w_n^i+1)=1-(-1)^n ∏i=0n−1(wni+1)=1−(−1)n。
考虑 k ∣ n k|n k∣n的情况。 记 d = gcd ( j , k ) d=\gcd(j,k) d=gcd(j,k),此时 gcd ( j d , k d ) = 1 \gcd(\frac{j}{d},\frac{k}{d})=1 gcd(dj,dk)=1:
f ( w k j ) = ∏ i = 0 n − 1 ( 1 + w k i j ) = ∏ i = 0 k d − 1 ( 1 + w k d i ) n d k = ( 1 − ( − 1 ) k d ) n d k \begin{aligned}f(w_k^j)&=\prod_{i=0}^{n-1}(1+w_k^{ij})\\&=\prod_{i=0}^{\frac{k}{d}-1}(1+w_{\frac{k}{d}}^{i})^{\frac{nd}{k}}\\&=(1-(-1)^{\frac{k}{d}})^{\frac{nd}{k}}\end{aligned} f(wkj)=i=0∏n−1(1+wkij)=i=0∏dk−1(1+wdki)knd=(1−(−1)dk)knd
带入原式即: 1 k ∑ j = 0 k − 1 w k − j r ( 1 − ( − 1 ) k d ) n d k \frac{1}{k}\sum_{j=0}^{k-1}w_k^{-jr}(1-(-1)^{\frac{k}{d}})^{\frac{nd}{k}} k1∑j=0k−1wk−jr(1−(−1)dk)knd,现在考虑怎么把前面的单位根搞掉。看到 gcd \gcd gcd考虑枚举 d d d,即:
L H S = 1 k ∑ d ∣ k ( 1 − ( − 1 ) k d ) n d k ∑ gcd ( j , k ) = d w k − j r LHS=\frac{1}{k}\sum_{d|k}(1-(-1)^{\frac{k}{d}})^{\frac{nd}{k}}\sum_{\gcd(j,k)=d}w_k^{-jr} LHS=k1d∣k∑(1−(−1)dk)kndgcd(j,k)=d∑wk−jr
后面那一坨看起来就很好化简:
∑ gcd ( j , k ) = d w k − j r = ∑ i = 1 k d w k − i d r [ gcd ( i , k d ) = 1 ] = ∑ i = 1 k d w k − i d r ∑ j ∣ gcd ( i , k d ) μ ( j ) = ∑ j ∣ k d μ ( j ) ∑ i = 1 k d j w k − i j d r = ∑ j ∣ k d μ ( j ) ∑ i = 1 k d j w k d j − r i = ∑ j ∣ k d μ ( j ) [ k d j ∣ r ] \begin{aligned}\sum_{\gcd(j,k)=d}w_k^{-jr}&=\sum_{i=1}^{\frac{k}{d}}w_k^{-idr}[\gcd(i,\frac{k}{d})=1]\\&=\sum_{i=1}^{\frac{k}{d}}w_k^{-idr}\sum_{j|\gcd(i,\frac{k}{d})}\mu(j)\\&=\sum_{j|\frac{k}{d}}\mu(j)\sum_{i=1}^{\frac{k}{dj}}w_k^{-ijdr}\\&=\sum_{j|\frac{k}{d}}\mu(j)\sum_{i=1}^{\frac{k}{dj}}w_\frac{k}{dj}^{-ri}\\&=\sum_{j|\frac{k}{d}}\mu(j)[\frac{k}{dj}|r]\end{aligned} gcd(j,k)=d∑wk−jr=i=1∑dkwk−idr[gcd(i,dk)=1]=i=1∑dkwk−idrj∣gcd(i,dk)∑μ(j)=j∣dk∑μ(j)i=1∑djkwk−ijdr=j∣dk∑μ(j)i=1∑djkwdjk−ri=j∣dk∑μ(j)[djk∣r]
最后一步是 逆用单位根反演 。因此最终答案为:
L H S = 1 k ∑ d ∣ k ( 1 − ( − 1 ) k d ) n d k g ( d , k ) \begin{aligned}LHS=\frac{1}{k}\sum_{d|k}(1-(-1)^{\frac{k}{d}})^{\frac{nd}{k}}g(d,k)\end{aligned} LHS=k1d∣k∑(1−(−1)dk)kndg(d,k)
其中 g ( d , k ) g(d,k) g(d,k)是固定的系数。现在考虑二元 G F GF GF,即 [ x i k + r y n ] ∏ i = 0 n − 1 ( 1 + x i y ) [x^{ik+r}y^n]\prod_{i=0}^{n-1}(1+x^iy) [xik+ryn]∏i=0n−1(1+xiy)。前面的推导都一模一样(把 y y y当成参量来处理),不难验证答案为:
L H S = 1 k ∑ d ∣ k ( 1 − ( − y ) k d ) n d k g ( d , k ) LHS=\frac{1}{k}\sum_{d|k}(1-(-y)^{\frac{k}{d}})^{\frac{nd}{k}}g(d,k) LHS=k1d∣k∑(1−(−y)dk)kndg(d,k)
对于 n ∤ k n\nmid k n∤k的情况,可以将剩余的不足 k k k项暴力背包,即设 f i , j f_{i,j} fi,j表示选了 i i i个数,并且模 k k k等于 j j j的方案数。可以在 O ( k 3 ) O(k^3) O(k3)的时间内处理出来,最后合并答案也是 O ( k 3 ) O(k^3) O(k3)的。
cpp
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std;
const int mod=998244353;
const int N=505;
const int M=2e6+5;
int n,m,p,n2,mx;
ll now[N][N];
ll fac[M],inv[M],f[N],g[N][N],res[N];
ll fpow(ll x,ll y=mod-2){
ll z(1);
for(;y;y>>=1){
if(y&1)z=z*x%mod;
x=x*x%mod;
}return z;
}
void init(int n){
fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
inv[n]=fpow(fac[n]);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod;
}
int mu[N],vs[N];
int pr[N],cnt;
void init2(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(vs[i]==0)pr[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&pr[j]<=n/i;j++){
vs[i*pr[j]]=1;
if(i%pr[j]==0){
mu[i*pr[j]]=0;
break;
}mu[i*pr[j]]=-mu[i];
}
}
}
ll binom(int x,int y){
if(x<0||y<0||x<y)return 0;
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
void add(ll &x,ll y){
x=(x+y)%mod;
}
vector<int>v;
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m>>p,n2=n+m;
init(n2),init2(p);
mx=p*(n2/p);
for(int i=1;i<=p;i++){
if(p%i==0)v.pb(i);
}
for(int k=0;k<p;k++){
for(auto d:v){
for(auto j:v){
if(p/d%j==0&&k%(p/d/j)==0){
add(g[k][d],mu[j]*p/d/j);
}
}
}
}
now[0][0]=1;
for(int i=mx;i<n2;i++){
int s=i%p;
for(int j=min(n2-mx,n);j>=1;j--){
for(int k=0;k<p;k++){
add(now[j][k],now[j-1][(k-s+p)%p]);
}
}
}
for(int i=0;i<=min(n,n2-mx);i++){
memset(f,0,sizeof f);
for(auto d:v){
if((n-i)%(p/d))continue;
int t=(n-i)/(p/d);
for(int k=0;k<p;k++){
if(p/d%2==1||t%2==0){
add(f[k],binom(d*mx/p,t)*g[k][d]);
}
else{
add(f[k],-binom(d*mx/p,t)*g[k][d]);
}
}
}
for(int j=0;j<p;j++){
for(int k=0;k<p;k++){
add(res[(j+k)%p],f[j]*now[i][k]);
}
}
}for(int i=0;i<p;i++){
res[i]=res[i]*fpow(p)%mod;
}int tmp=(ll)n*(n-1)/2%p;
for(int i=0;i<p;i++){
cout<<(res[(i+tmp)%p]+mod)%mod<<" ";
}
}