题目描述
题目分析
设有 i i i 行选了奇数次的方案数为 f i f_i fi, j j j 列选了奇数次的方案数为 g j g_j gj
A n s = ∑ i m + j n − 2 i j ≤ k f i ∗ g j Ans=\sum_{im+jn-2ij\le k} f_i*g_j Ans=∑im+jn−2ij≤kfi∗gj
f i = q ! [ x q ] ( e x − e − x 2 ) i ( e x + e − x 2 ) n − i ( n i ) f_i=q![x^q](\frac {e^x-e^{-x}}2)^i(\frac {e^x+e^{-x}}2)^{n-i}\binom ni fi=q![xq](2ex−e−x)i(2ex+e−x)n−i(in)
直接推不太好推(但是是可行的,有个小技巧,下面会讲到)
如果只有一个有幂会舒服一点。考虑二项式反演, h i h_i hi 为强制有 i i i 行奇数,其余任意的方案。
h
i
=
q
!
[
x
q
]
(
e
x
−
e
−
x
2
)
i
e
(
n
−
i
)
x
(
n
i
)
=
(
1
2
)
i
(
n
i
)
q
!
[
x
q
]
∑
j
=
0
i
(
i
j
)
(
−
1
)
i
−
j
e
x
(
n
−
2
i
+
2
j
)
h_i=q![x^q](\frac {e^x-e^{-x}}2)^ie^{(n-i)x}\binom ni\\ =(\frac 12)^i\binom niq![x^q]\sum_{j=0}^i\binom ij(-1)^{i-j}e^{x(n-2i+2j)}
hi=q![xq](2ex−e−x)ie(n−i)x(in)=(21)i(in)q![xq]j=0∑i(ji)(−1)i−jex(n−2i+2j)
而
q
!
[
x
q
]
e
x
(
n
−
2
i
+
2
j
)
=
(
n
−
2
i
+
2
j
)
q
q![x^q]e^{x(n-2i+2j)}=(n-2i+2j)^q
q![xq]ex(n−2i+2j)=(n−2i+2j)q
然后就可以卷积了。
二项式反演还要再卷一次。
算完 f , g f,g f,g 后枚举 i i i, j ( n − 2 i ) ≤ k − i m j(n-2i)\le k-im j(n−2i)≤k−im,根据 n − 2 i n-2i n−2i 的正负求对应的前缀和即可。
注意负数除法下取整是变大的。
然后说一说怎么不用二项式反演直接推式子。
对于那两个很像的底数,把一个用另一个的形式表示,即:
q
!
[
x
q
]
(
n
i
)
(
1
2
)
n
(
e
x
−
e
−
x
)
i
(
e
x
+
e
−
x
)
n
−
i
=
q
!
[
x
q
]
(
n
i
)
(
1
2
)
n
(
e
x
+
e
−
x
−
2
e
−
x
)
i
(
e
x
+
e
−
x
)
n
−
i
=
q
!
[
x
q
]
(
n
i
)
(
1
2
)
n
∑
j
=
0
i
(
−
2
)
i
−
j
(
e
x
+
e
−
x
)
n
−
i
+
j
e
−
x
(
i
−
j
)
=
q
!
[
x
q
]
(
n
i
)
(
1
2
)
n
∑
j
=
0
i
(
−
2
)
i
−
j
∑
k
=
0
n
−
i
+
j
(
n
−
i
+
j
k
)
e
(
2
k
−
n
)
x
=
(
n
i
)
(
1
2
)
n
∑
j
=
0
i
(
−
2
)
i
−
j
∑
k
=
0
n
−
i
+
j
(
n
−
i
+
j
k
)
(
2
k
−
n
)
q
q![x^q]\binom ni(\frac 12)^n(e^x-e^{-x})^i(e^x+e^{-x})^{n-i}\\ =q![x^q]\binom ni(\frac 12)^n(e^x+e^{-x}-2e^{-x})^i(e^x+e^{-x})^{n-i}\\ =q![x^q]\binom ni(\frac 12)^n\sum_{j=0}^i(-2)^{i-j}(e^x+e^{-x})^{n-i+j}e^{-x(i-j)}\\ =q![x^q]\binom ni(\frac 12)^n\sum_{j=0}^i(-2)^{i-j}\sum_{k=0}^{n-i+j}\binom {n-i+j}ke^{(2k-n)x}\\ =\binom ni(\frac 12)^n\sum_{j=0}^i(-2)^{i-j}\sum_{k=0}^{n-i+j}\binom {n-i+j}k(2k-n)^q
q![xq](in)(21)n(ex−e−x)i(ex+e−x)n−i=q![xq](in)(21)n(ex+e−x−2e−x)i(ex+e−x)n−i=q![xq](in)(21)nj=0∑i(−2)i−j(ex+e−x)n−i+je−x(i−j)=q![xq](in)(21)nj=0∑i(−2)i−jk=0∑n−i+j(kn−i+j)e(2k−n)x=(in)(21)nj=0∑i(−2)i−jk=0∑n−i+j(kn−i+j)(2k−n)q
第二个
∑
\sum
∑ 可以看作
G
(
i
−
j
)
G(i-j)
G(i−j),一次卷积可以求出
G
G
G,然后再卷一次就可以求出
f
f
f 了。
Code(二项式反演):
#include<bits/stdc++.h>
#define maxn 550005
using namespace std;
const int mod = 998244353, inv2 = (mod+1)/2;
int w[maxn],r[maxn],WL,fac[maxn],inv[maxn];
int Pow(int a,int b){int s=1;for(;b;b>>=1,a=1ll*a*a%mod) b&1&&(s=1ll*s*a%mod);return s;}
int C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;}
void init(int n){
w[0]=WL=1; while(WL<=n) WL<<=1; w[1]=Pow(3,(mod-1)/WL);
for(int i=2;i<=WL;i++) w[i]=1ll*w[i-1]*w[1]%mod;
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=2;i<=n;i++) inv[i]=1ll*inv[i-1]*inv[i]%mod;
}
int upd(int x){return x+(x>>31&mod);}
void NTT(int *a,int len,int flg){
for(int i=0;i<len;i++) if(i<(r[i]=r[i>>1]>>1|(i&1?len>>1:0))) swap(a[i],a[r[i]]);
for(int i=2,l=1,v;i<=len;l=i,i<<=1)
for(int j=0,t=WL/i;j<len;j+=i)
for(int k=j,o=0;k<j+l;k++,o+=t)
a[k+l]=upd(a[k]-(v=1ll*w[flg^1?WL-o:o]*a[k+l]%mod)),a[k]=upd(a[k]+v-mod);
if(flg^1) for(int i=0,Inv=mod-(mod-1)/len;i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
int n,m,qq,A[maxn],B[maxn],f[maxn],g[maxn],h[maxn];
long long q,k,lim;
void calc(int n,int *f){
init(2*n);
memset(A,0,sizeof A),memset(B,0,sizeof B);
for(int i=0;i<=n;i++) A[i]=inv[i],B[i]=1ll*(i&1?mod-1:1)*inv[i]%mod*Pow(upd(n-2*i),qq)%mod;
NTT(A,WL,1),NTT(B,WL,1);
for(int i=0;i<WL;i++) A[i]=1ll*A[i]*B[i]%mod;
NTT(A,WL,-1); memset(h,0,sizeof h);
for(int i=0,pw=1;i<=n;i++,pw=1ll*pw*inv[2]%mod) h[i]=1ll*A[i]*fac[n]%mod*inv[n-i]%mod*pw%mod;
memset(A,0,sizeof A),memset(B,0,sizeof B);
for(int i=0;i<=n;i++) A[i]=1ll*h[i]*fac[i]%mod,B[i]=1ll*inv[n-i]*(n-i&1?mod-1:1)%mod;
NTT(A,WL,1),NTT(B,WL,1);
for(int i=0;i<WL;i++) A[i]=1ll*A[i]*B[i]%mod;
NTT(A,WL,-1);
for(int i=0;i<=n;i++) f[i]=1ll*A[n+i]*inv[i]%mod;
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
scanf("%d%d%lld%lld",&n,&m,&q,&k),qq=q%(mod-1);
if(q==0) return puts("1"),0;
calc(n,f),calc(m,g);
for(int i=1;i<=m;i++) g[i]=(g[i]+g[i-1])%mod;
int ans=0;
for(int i=0;i<=n;i++)
if(n>2*i){
if(k>=1ll*i*m) ans=(ans+1ll*f[i]*g[min((k-1ll*i*m)/(n-2*i),1ll*m)])%mod;
}
else if(n<2*i){
if((lim=(1ll*i*m-k+2*i-n-1)/(2*i-n))<=m) ans=(ans+1ll*f[i]*(g[m]-(lim>0?g[lim-1]:0)))%mod;
}
else if(k-1ll*i*m>=0) ans=(ans+1ll*f[i]*g[m])%mod;
printf("%d\n",(ans+mod)%mod);
}