聯考20200727 T2 小$\omega$玩遊戲
分析:
又被開除人籍了。。
首先我們要把行和列分開計算
假設\(n\)行中有\(i\)個被訪問了奇數次,\(m\)列中有\(j\)個被訪問了奇數次
那麼最終的奇數點數可以計算為\((n-i)j+(m-j)i\)
(然而這步我都沒想到,7分暴力走人。。。
於是我們把行列分開處理做\(q\)次
我們現在只看行,列做同樣處理
設\(f_i\)表示\(n\)行做了\(q\)次裡面恰好有\(i\)行為奇數
看樣子像是要用生成函式去表示它
啥啊,我是廢物不會啊
考慮容斥,設\(g_i\)表示\(n\)行做了\(q\)次裡面至少有\(i\)行為奇數
關係式為:
\(g_i=\sum_{j=i}^{n}f_i\)
二項式反演:
\(f_i=\sum_{j=i}^{n}(-1)^{j-i}g_i\)
我們知道了\(g\),這個卷積形式喜聞樂見NTT就可以處理出\(f\)
來算\(g\)
先把\(i\)個必為奇數的放到前面,最後係數乘一個\(\binom{n}{i}\)就好
表示奇數位並帶階乘逆元的生成函式是\(\frac{e^x-e^{-x}}{2}\)
所以
\[g_i=\binom{n}{i}q![x^q](\frac{e^x-e^{-x}}{2})^i(e^x)^{n-i} \]
取第\(q\)項,前面的\(q!\)會和生成函式第\(q\)項的階乘逆元抵消
用一下二項式定理:
\[g_i=\binom{n}{i}2^{-i}\sum_{j=0}^{i}(-1)^{i-j}\binom{i}{j}q![x^q]e^{(n−2i+2j)x} \]
\[g_i=\binom{n}{i}2^{-i}\sum_{j=0}^{i}(-1)^{i-j}\binom{i}{j}(n−2i+2j)^q \]
喜聞樂見NTT可以求\(g\)
之後再用NTT求\(f\)
行和列都得到了各自的\(f\)
我們設一個為\(f\)一個為\(g\)吧
考慮式子:
\[Ans=\sum_{(n-i)j+(m-j)i\leq k}f_ig_j \]
我們列舉\(i\),合法的\(j\)是一個區間
那麼我們對\(g\)求一個字首和,分類討論計算即可
討論起來有點噁心,而且注意開long long
複雜度\(O(nlogn)\)
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #include<string> #define maxn 1000005 #define INF 0x3f3f3f3f #define MOD 998244353 using namespace std; inline long long getint() { long long num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,m,len; long long q,k; int a[maxn],b[maxn]; int f[maxn],g[maxn],sum[maxn]; int rev[maxn]; int fac[maxn],inv[maxn]; inline int upd(int x){return x<MOD?x:x-MOD;} inline int C(int p,int q) {return 1ll*fac[p]*inv[q]%MOD*inv[p-q]%MOD;} inline int ksm(int num,int k) { int ret=1; for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD; return ret; } inline void NTT(int *a,int N,int opt) { for(int i=0;i<N;i++)if(rev[i]<i)swap(a[i],a[rev[i]]); for(int i=1;i<N;i<<=1) { int wn=ksm(3,(MOD-1)/(i<<1)); if(!~opt)wn=ksm(wn,MOD-2); for(int j=0;j<N;j+=i<<1)for(int k=0,w=1;k<i;k++,w=1ll*w*wn%MOD) { int x=a[j+k],y=1ll*w*a[i+j+k]%MOD; a[j+k]=upd(x+y),a[i+j+k]=upd(x-y+MOD); } } if(!~opt)for(int i=0,Inv=ksm(N,MOD-2);i<N;i++)a[i]=1ll*a[i]*Inv%MOD; } inline void solve(int n,int *f) { for(int i=0;i<len;i++)a[i]=b[i]=0; for(int i=0;i<=n;i++)a[i]=inv[i]; for(int i=0;i<=n;i++)b[i]=1ll*(i&1?MOD-1:1)*inv[i]%MOD*ksm(upd(n-2*i+MOD),q%(MOD-1))%MOD; NTT(a,len,1),NTT(b,len,1); for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%MOD; NTT(a,len,-1); for(int i=0;i<=n;i++)f[i]=1ll*a[i]*ksm(inv[2],i)%MOD*fac[n]%MOD*inv[n-i]%MOD; for(int i=0;i<len;i++)a[i]=b[i]=0; for(int i=0;i<=n;i++)a[i]=1ll*f[i]*fac[i]%MOD; for(int i=0;i<=n;i++)b[n-i]=1ll*(i&1?MOD-1:1)*inv[i]%MOD; NTT(a,len,1),NTT(b,len,1); for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%MOD; NTT(a,len,-1); for(int i=0;i<=n;i++)f[i]=1ll*a[i+n]*inv[i]%MOD; } int main() { n=getint(),m=getint(),q=getint(),k=getint(); if(!n||!m){printf("0\n");return 0;} if(n<m)swap(n,m); fac[0]=fac[1]=inv[0]=inv[1]=1; for(int i=2;i<=n;i++)fac[i]=1ll*fac[i-1]*i%MOD; for(int i=2;i<=n;i++)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD; for(int i=2;i<=n;i++)inv[i]=1ll*inv[i]*inv[i-1]%MOD; len=1; while(len<=2*n)len<<=1; for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0); solve(n,f),solve(m,g); for(int i=1;i<=m;i++)g[i]=upd(g[i-1]+g[i]); int ans=0; for(int i=0;i<=n;i++) { if(n>2*i) { long long p=floor((k-1.0*i*m)/(n-2*i)); if(p>=0)ans=upd(ans+1ll*f[i]*g[min(1ll*m,p)]%MOD); } else if(n<2*i) { long long p=ceil((k-1.0*i*m)/(n-2*i)); if(p<=m)ans=upd(ans+1ll*f[i]*upd(g[m]-(p>0?g[p-1]:0)+MOD)%MOD); } else if(k-1ll*i*m>=0)ans=upd(ans+1ll*f[i]*g[m]%MOD); } printf("%d\n",ans); }