【WC2014】时空穿梭【组合数】【莫比乌斯反演】【整除分块】【暴力多项式】
題意:TTT 組數(shù)據(jù),給一個(gè) nnn 維空間,第 iii 維大小為 [1,mi]∩Z[1,m_i]\cap \Z[1,mi?]∩Z,求大小為 ccc 的嚴(yán)格偏序上升的共線點(diǎn)集個(gè)數(shù)。答案模 100071000710007。
T≤100,n≤11,m≤105,c≤20T\leq 100,n\leq 11,m\leq 10^5,c\leq 20T≤100,n≤11,m≤105,c≤20
神仙題
設(shè)空間大小向量為 mmm,MMM 為坐標(biāo)最大值。下文中若未特殊說明,對(duì)向量無(wú)公開定義的運(yùn)算均定義為其每一維坐標(biāo)的運(yùn)算。
考慮第一個(gè)點(diǎn)到最后一個(gè)點(diǎn)的差向量 xxx,它中間有 gcd?(x)?1\gcd(x)-1gcd(x)?1 個(gè)空隙可以放,gcd?\gcdgcd 為所有坐標(biāo)數(shù)值的 gcd?\gcdgcd。所以
ans=∑x≤m(gcd?(x)?1c?2)∏i=1n(mi?xi)ans=\sum_{x\leq m}\binom{\gcd(x)-1}{c-2}\prod_{i=1}^n(m_i-x_i)ans=x≤m∑?(c?2gcd(x)?1?)i=1∏n?(mi??xi?)
看到有個(gè) gcd?\gcdgcd ,想到反演。
ans=∑d=1M(d?1c?2)∑x≤m[gcd?(x)=d]∏i=1n(mi?xi)=∑d=1M(d?1c?2)∑x≤md[gcd?(x)=1]∏i=1n(mi?dxi)=∑d=1M(d?1c?2)∑x≤md∑k∣xμ(k)∏i=1n(mi?dxi)=∑d=1M(d?1c?2)∑k∣xμ(k)∑x≤mdk∏i=1n(mi?dkxi)=∑d=1M∑x≤md∏i=1n(mi?dxi)∑k∣d(k?1c?2)μ(dk)ans=\sum_{d=1}^M\binom{d-1}{c-2}\sum_{x\leq m}[\gcd(x)=d]\prod_{i=1}^n(m_i-x_i)\\ =\sum_{d=1}^M\binom{d-1}{c-2}\sum_{x\leq \frac{m}ze8trgl8bvbq}[\gcd(x)=1]\prod_{i=1}^n(m_i-dx_i)\\ =\sum_{d=1}^M\binom{d-1}{c-2}\sum_{x\leq \frac{m}ze8trgl8bvbq}\sum_{k\mid x}\mu (k)\prod_{i=1}^n(m_i-dx_i)\\ =\sum_{d=1}^M\binom{d-1}{c-2}\sum_{k\mid x}\mu (k)\sum_{x\leq \frac{m}{dk}}\prod_{i=1}^n(m_i-dkx_i)\\ =\sum_{d=1}^M\sum_{x\leq \frac md}\prod_{i=1}^n(m_i-dx_i)\sum_{k\mid d}\binom{k-1}{c-2}\mu (\frac dk)ans=d=1∑M?(c?2d?1?)x≤m∑?[gcd(x)=d]i=1∏n?(mi??xi?)=d=1∑M?(c?2d?1?)x≤dm?∑?[gcd(x)=1]i=1∏n?(mi??dxi?)=d=1∑M?(c?2d?1?)x≤dm?∑?k∣x∑?μ(k)i=1∏n?(mi??dxi?)=d=1∑M?(c?2d?1?)k∣x∑?μ(k)x≤dkm?∑?i=1∏n?(mi??dkxi?)=d=1∑M?x≤dm?∑?i=1∏n?(mi??dxi?)k∣d∑?(c?2k?1?)μ(kd?)
令 g(n)=∑d∣n(d?1c?2)μ(nd)g(n)=\sum\limits_{d\mid n}\binom{d-1}{c-2}\mu(\frac nd)g(n)=d∣n∑?(c?2d?1?)μ(dn?),這個(gè)隨便預(yù)處理一下就能算出來(lái)。
ans=∑d=1M∑x≤md∏i=1n(mi?dxi)g(d)=∑d=1Mg(d)∏i=1n∑x=1?mid?(mi?dx)ans=\sum_{d=1}^M\sum_{x\leq \frac md}\prod_{i=1}^n(m_i-dx_i)g(d)\\ =\sum_{d=1}^Mg(d)\prod_{i=1}^n\sum_{x=1}^{\left\lfloor\frac{m_i}ze8trgl8bvbq\right\rfloor}(m_i-dx)ans=d=1∑M?x≤dm?∑?i=1∏n?(mi??dxi?)g(d)=d=1∑M?g(d)i=1∏n?x=1∑?dmi????(mi??dx)
這樣大概是 O(Tmnlog?n)\Omicron(Tmn\log n)O(Tmnlogn) 的,有點(diǎn)卡。
看到整除,立刻想到整除分塊。
注意到后面是一個(gè)關(guān)于 ddd 的 nnn 次多項(xiàng)式(每個(gè)和式次數(shù)為 111),如果要整除分塊的話只需要求這個(gè)多項(xiàng)式的前綴和。
設(shè)這個(gè)多項(xiàng)式系數(shù)為 aia_iai?,那么一次區(qū)間查詢
∑d=lrg(d)f(d)=∑d=lrg(d)∑i=0naidi=∑i=0nai∑d=lrg(d)di\sum_{d=l}^rg(d)f(d)\\ =\sum_{d=l}^rg(d)\sum_{i=0}^na_id^i\\ =\sum_{i=0}^na_i\sum_{d=l}^rg(d)d^id=l∑r?g(d)f(d)=d=l∑r?g(d)i=0∑n?ai?di=i=0∑n?ai?d=l∑r?g(d)di
后面是和詢問無(wú)關(guān)的,直接預(yù)處理就可以 O(n)\Omicron(n)O(n) 回答。
現(xiàn)在的問題是如何維護(hù)多項(xiàng)式。 整除分塊時(shí)一共變化了 O(nm)\Omicron(n\sqrt m)O(nm?) 次,每次變化的時(shí)候把操作的 111 次多項(xiàng)式做一個(gè)多項(xiàng)式乘法或除法就可以了。
然后是喜聞樂見的除 000 問題。記下除了幾個(gè) 000 多項(xiàng)式即可,但其他人都沒提到這個(gè),代碼也看不懂,一臉懵逼,可能寫法不太一樣吧……
復(fù)雜度大概是 O(ncm+Tn2m)\Omicron(ncm+Tn^2\sqrt m)O(ncm+Tn2m?)
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> using namespace std; typedef long long ll; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } const int MOD=10007; inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;} inline int dec(const int& x,const int& y){return x<y? x-y+MOD:x-y;} inline int qpow(int a,int p) {int ans=1;a%=MOD;while (p){if (p&1) ans=ans*a%MOD;a=a*a%MOD,p>>=1;}return ans; } const int N=1e5,MAXN=N+5; int np[MAXN],pl[MAXN],cnt; inline void init() {np[1]=1;for (int i=2;i<=N;i++){if (!np[i]) pl[++cnt]=i;for (int j=1,x;(x=i*pl[j])<=N;j++){np[x]=1;if (i%pl[j]==0) break;}} } int C[MAXN][20],g[22][MAXN],S[12][22][MAXN]; int a[12],n,c,lim[12],m[12],zero; inline void mul(int x,int y) {if (!x&&!y) return (void)(++zero);for (int i=n;i>=1;i--) a[i]=(a[i-1]*x+a[i]*y)%MOD;a[0]=a[0]*y%MOD; } inline void div(int x,int y) {if (!y){if (!x) return (void)(--zero);int ix=qpow(x,MOD-2);for (int i=0;i<n;i++) a[i]=a[i+1]*ix%MOD;a[n]=0; return;}int iy=qpow(y,MOD-2);a[0]=a[0]*iy%MOD;for (int i=1;i<=n;i++) a[i]=dec(a[i],a[i-1]*x%MOD)*iy%MOD; } inline int calc(int d,int l,int r) {for (int i=1;i<=n;i++){int cur=m[i]/d;if (cur<lim[i]){div(dec(0,lim[i]*(lim[i]+1ll)/2%MOD),(ll)lim[i]*m[i]%MOD);lim[i]=cur;mul(dec(0,lim[i]*(lim[i]+1ll)/2%MOD),(ll)lim[i]*m[i]%MOD);}}if (zero) return 0;int ans=0;for (int i=0;i<=n;i++) ans=(ans+a[i]*dec(S[i][c][r],S[i][c][l-1]))%MOD;return ans; } int main() {init();C[0][0]=1;for (int i=1;i<=N;i++){C[i][0]=1;for (int j=1;j<20;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;}for (int t=2;t<22;t++){for (int i=1;i<=N;i++) g[t][i]=C[i-1][t-2];for (int j=1;j<=cnt;j++)for (int i=N/pl[j];i>=1;i--)g[t][i*pl[j]]=dec(g[t][i*pl[j]],g[t][i]);for (int i=0;i<12;i++)for (int d=1;d<=N;d++)S[i][t][d]=add(S[i][t][d-1],qpow(d,i)*g[t][d]%MOD); }for (int T=read();T;T--){zero=0;n=read(),c=read();int M=N;for (int i=1;i<=n;i++) M=min(M,lim[i]=m[i]=read());memset(a,0,sizeof(a));a[0]=1;for (int i=1;i<=n;i++) mul(dec(0,m[i]*(m[i]+1ll)/2%MOD),(ll)m[i]*m[i]%MOD);int ans=0;for (int l=1,r;l<=M;l=r+1){r=M;for (int i=1;i<=n;i++) r=min(r,m[i]/(m[i]/l));ans=add(ans,calc(l,l,r));}printf("%d\n",ans);}return 0; }總結(jié)
以上是生活随笔為你收集整理的【WC2014】时空穿梭【组合数】【莫比乌斯反演】【整除分块】【暴力多项式】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宝宝面黄肌瘦,不爱吃饭怎么办
- 下一篇: 12岁女生怎么减肥