21.7.10 t2
阿新 • • 發佈:2021-07-10
tag:fwt,多項式快速冪
這是一道看上去很難的題。
但是你仔細分析一下就會發現,\(c_i\) 沒用。。
因為有個 \(\mu\) 的存在,所以只需 \(2^k\) 列舉所有情況計算。
然後問題在於如何快速計算。
對於 \(f^a(x)\),由於 \(x\) 一定可以表示為 \(p_1\times\cdots\times p_k\),所以實際上相當於是
\[f^a(x)=\sum_{\bigcap S_i=[1,k],\forall i!=j,S_i\cup S_j=\varnothing}f(\prod S_i) \]用人話來講就是,把 \(k\) 個質數分為 \(a\) 組(可以有空組),每組的貢獻為 \(f(\prod p)\)
對於 \(\phi^a(x)\),由於 \(\phi\) 是積性函式,所以不管怎麼分組貢獻都是 \(\phi(x)\),而分組方案為 \(a^k\),所以 \(\phi^a(x)=a^k\phi(x)\)。
對於 \(f^b(x)\) 就沒有比較直接的方法了。
這個時候我們看到資料範圍有一個 \(k\le16,b\le8\),於是想到暴力 dp。
設 \(f[i][S]\) 表示前 \(i\) 組分了 \(S\),轉移時列舉子集,複雜度 \(O(b3^k)\)。
然後我們又看到了資料範圍有一個 \(k\le18,b\le8\),於是想到了不交併卷積
然後我們發現不交併中間的步驟可以表示為一個長度為 \(k\) 的多項式 \(F_i=f[i][S]\) 的 \(b\) 次方,於是我們想到了執行 \(2^k\) 次多項式快速冪。
然後我們發現 fwt 後 \(f[0][S]=1\),於是想到了 \(\ln\) 然後 \(\exp\)。
複雜度 \(O(2^kk^2)\)。
#include<bits/stdc++.h> using namespace std; template<typename T> inline void Read(T &n){ char ch; bool flag=false; while(!isdigit(ch=getchar()))if(ch=='-')flag=true; for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48)); if(flag)n=-n; } typedef long long ll; enum{ MOD = 998244353 }; inline int ksm(int base, ll k=MOD-2){ int res=1; while(k){ if(k&1) res = 1ll*res*base%MOD; base = 1ll*base*base%MOD; k >>= 1; } return res; } inline int inc(int a, int b){ a += b; if(a>=MOD) a -= MOD; return a; } inline int dec(int a, int b){ a -= b; if(a<0) a += MOD; return a; } inline void iinc(int &a, int b){a = inc(a,b);} inline void ddec(int &a, int b){a = dec(a,b);} inline void upd(int &a, long long b){a = (a+b)%MOD;} int p[20], c[20]; int k, ans; ll a, b; namespace Case2{ inline void fwt(int *f, int n, int flag){ for(int len=2; len<=n; len<<=1) for(int l=0; l<n; l+=len) for(int i=l; i<l+len/2; i++) if(flag==1) iinc(f[i+len/2],f[i]); else ddec(f[i+len/2],f[i]); } int f[19][1<<18], cnt[1<<18], tmp[19][1<<18]; int F[20], G[20], inv[20]; inline void solve(){ int tp=1<<k; for(int i=1; i<=k; i++) inv[i] = ksm(i); for(int s=0; s<tp; s++){ int mul=1; for(int i=0; i<k; i++) if(s>>i&1) mul = 1ll*mul*p[i]%MOD, cnt[s]++; f[cnt[s]][s] = 1; upd(f[cnt[s]][s],1ll*mul*mul); ddec(f[cnt[s]][s],mul); } for(int i=0; i<=k; i++) fwt(f[i],tp,1); for(int s=0; s<tp; s++){ for(int i=0; i<=k; i++) F[i] = f[i][s]; for(int i=1; i<=k; i++){ G[i] = 0; for(int j=1; j<i; j++) ddec(G[i],1ll*j*G[j]%MOD*F[i-j]%MOD); G[i] = (F[i]+1ll*inv[i]*G[i])%MOD; } G[0] = 0; for(int i=1; i<=k; i++) G[i] = b*G[i]%MOD; for(int i=1; i<=k; i++){ int tmp=0; for(int j=1; j<=i; j++) upd(tmp,1ll*j*G[j]%MOD*F[i-j]); F[i] = 1ll*tmp*inv[i]%MOD; } F[0] = 1; for(int i=0; i<=k; i++) f[i][s] = F[i]; } for(int i=0; i<=k; i++) fwt(f[i],tp,-1); for(int s=0; s<tp; s++){ int phi=1; for(int i=0; i<k; i++) if(s>>i&1) phi = 1ll*phi*(p[i]-1)%MOD; phi = 1ll*phi*ksm(a,cnt[s])%MOD; if(cnt[s]&1) ddec(ans,1ll*phi*f[cnt[s]][s]%MOD); else upd(ans,1ll*phi*f[cnt[s]][s]); // for(int i=0; i<k; i++) putchar(s>>i&1^48); printf(" %d\n",phi); } cout<<ans<<'\n'; } } int main(){ // freopen("dirichlet3.in","r",stdin); Read(a); Read(b); Read(k); a %= MOD; b %= MOD; for(int i=0; i<k; i++) Read(p[i]), Read(c[i]); // if(a<=8 and b<=8) return Case2::solve(); return 0; } /* 1 2 3 2 1 3 2 5 4 */