CF755G-PolandBall and Many Other Balls【倍增FFT】
正題
題目鏈接:https://www.luogu.com.cn/problem/CF755G
題目大意
nnn個(gè)東西排成一排,每個(gè)組可以選擇一個(gè)單獨(dú)的物品或者兩個(gè)連續(xù)的物品,一個(gè)物品不同同時(shí)在兩個(gè)組里,但是可以不在組里。對于i∈[1,k]i\in[1,k]i∈[1,k]求分成iii組的方案數(shù)。
1≤n≤109,1≤k<2151\leq n\leq 10^9,1\leq k<2^{15}1≤n≤109,1≤k<215
解題思路
有三種方法。
第一種是倍增FFTFFTFFT,設(shè)fi,jf_{i,j}fi,j?表示到第iii個(gè)物品選了jjj組時(shí)的方案數(shù),那么設(shè)Fn(x)=∑i=0kfn,ixiF_n(x)=\sum_{i=0}^kf_{n,i}x^iFn?(x)=∑i=0k?fn,i?xi。
考慮把這個(gè)FFF分成兩半,然后考慮中間的選不選就是
Fn+m(x)=Fn(x)Fm(x)+xFn?1(x)Fm?1(x)F_{n+m}(x)=F_{n}(x)F_m(x)+xF_{n-1}(x)F_{m-1}(x)Fn+m?(x)=Fn?(x)Fm?(x)+xFn?1?(x)Fm?1?(x)
我們發(fā)現(xiàn)如果需要計(jì)算F2kF_{2^k}F2k?,那么我們就需要維護(hù)F2k?1,F2k?1?1,F2k?1?2F_{2^{k-1}},F_{2^{k-1}-1},F_{2^{k-1}-2}F2k?1?,F2k?1?1?,F2k?1?2?這三個(gè)東西。
但是這三個(gè)東西也可以用來計(jì)算F2k?1,F2k?2F_{2^k-1},F_{2^k-2}F2k?1?,F2k?2?,所以可以維護(hù)這三個(gè)東西就行倍增。
然后處理的時(shí)候同理維護(hù)一個(gè)FmF_{m}Fm?和Fm?1F_{m-1}Fm?1?就好了。
時(shí)間復(fù)雜度O(nlog?2n)O(n\log^2 n)O(nlog2n),有點(diǎn)卡常
…
第二種方法是直接組合數(shù)學(xué)推導(dǎo)。將這個(gè)序列提出若干段,每一段之間間隔為111,那么只有最末尾的段能夠長度為222的。
ansk=∑i=1k(n?ik)(ki)ans_k=\sum_{i=1}^k\binom{n-i}{k}\binom{k}{i}ansk?=i=1∑k?(kn?i?)(ik?)
瓶頸在于后面的(ki)\binom{k}{i}(ik?),也就是要求前后沒有重復(fù),所以我們可以考慮允許重復(fù)的容斥
?ansk=∑i=1k(?1)i(ki)(n?ik?i)2k?i\Rightarrow ans_k=\sum_{i=1}^k(-1)^{i}\binom{k}{i}\binom{n-i}{k-i}2^{k-i}?ansk?=i=1∑k?(?1)i(ik?)(k?in?i?)2k?i
?∑i=1k(?1)ik!i!(k?i)!(n?i)!(k?i)!(n?k)!2k?i\Rightarrow \sum_{i=1}^k(-1)^i\frac{k!}{i!(k-i)!}\frac{(n-i)!}{(k-i)!(n-k)!}2^{k-i}?i=1∑k?(?1)ii!(k?i)!k!?(k?i)!(n?k)!(n?i)!?2k?i
k!(n?k)!∑i=1k(?1)i(n?i)!i!×2k?i(k?i)!2\frac{k!}{(n-k)!}\sum_{i=1}^k\frac{(-1)^i(n-i)!}{i!}\times \frac{2^{k-i}}{(k-i)!^2}(n?k)!k!?i=1∑k?i!(?1)i(n?i)!?×(k?i)!22k?i?
就可以卷積了,時(shí)間復(fù)雜度O(nlog?n)O(n\log n)O(nlogn)
…
第三種方法是特征方程,回到第一個(gè)方法的Fn(x)F_n(x)Fn?(x),我們有
fi,j=fi?1,j+fi?1,j?1+fi?2,j?1f_{i,j}=f_{i-1,j}+f_{i-1,j-1}+f_{i-2,j-1}fi,j?=fi?1,j?+fi?1,j?1?+fi?2,j?1?
?Fn(x)=(1+x)Fn?1(x)+xFn?2(x)\Rightarrow F_n(x)=(1+x)F_{n-1}(x)+xF_{n-2}(x)?Fn?(x)=(1+x)Fn?1?(x)+xFn?2?(x)
這是一個(gè)二次項(xiàng)的遞推式,過程就不在論述了,用特征方程化簡可以得到
Fn(x)=(x+1?x2+6x+12)n+1x2+6x+1(modxn+1)F_{n}(x)=\frac{(\frac{x+1-\sqrt {x^2+6x+1}}{2})^{n+1}}{\sqrt{x^2+6x+1}}(mod\ x^{n+1})Fn?(x)=x2+6x+1?(2x+1?x2+6x+1??)n+1?(mod?xn+1)
然后上全家桶就好了,時(shí)間復(fù)雜度也是O(nlog?n)O(n\log n)O(nlogn)
這里的標(biāo)程用的是第一種方法。
code
#include<cstdio> #include<cstring> #include<algorithm> #define int long long using namespace std; const int N=1<<16,P=998244353; int n,k,m,r[N],f[3][N],t[3][N],g[2][N]; void fm(int &x){x+=x>>31&P;} int power(int x,int b){int ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans; } void NTT(int *f,int op){for(int i=0;i<n;i++)if(i<r[i])swap(f[i],f[r[i]]);for(int p=2;p<=n;p<<=1){int tmp=power(3,(P-1)/p),len=p>>1;if(op==-1)tmp=power(tmp,P-2);for(int k=0;k<n;k+=p){int buf=1;for(int i=k,tt;i<(k|len);i++){tt=1ll*buf*f[i|len]%P;fm(f[i|len]=f[i]-tt);fm(f[i]=f[i]+tt-P);buf=1ll*buf*tmp%P;}}}if(op==-1){int invn=power(n,P-2);for(int i=0;i<n;i++)f[i]=1ll*f[i]*invn%P;}return; } void print(int x) {if(x>9)print(x/10);putchar(x%10+'0');return;} signed main() {scanf("%d%d",&m,&k);k++;n=1;while(n<(k*2))n<<=1;for(int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)?(n>>1):0);f[0][0]=f[0][1]=f[1][0]=g[0][0]=1;for(int d=1;d<=m;d<<=1){if(m&d){for(int j=0;j<3;j++){for(int i=0;i<n;i++)t[j][i]=(i<k)?f[j][i]:0;NTT(t[j],1);}NTT(g[0],1);NTT(g[1],1);for(int i=0;i<n;i++){int b0=g[0][i],b1=g[1][i];g[0][i]=1ll*b0*t[0][i]%P;g[1][i]=1ll*b0*t[1][i]%P;t[0][i]=1ll*t[1][i]*b1%P;t[1][i]=1ll*t[2][i]*b1%P;}NTT(g[0],-1);NTT(g[1],-1);NTT(t[0],-1);NTT(t[1],-1);for(int i=0;i<k-1;i++)(g[0][i+1]+=t[0][i])%=P,(g[1][i+1]+=t[1][i])%=P;for(int i=k;i<n;i++)g[0][i]=g[1][i]=0;}if(d*2>m)break;for(int j=0;j<3;j++){for(int i=0;i<n;i++)t[j][i]=(i<k)?f[j][i]:0;NTT(t[j],1);}for(int i=0;i<n;i++){f[0][i]=1ll*t[0][i]*t[0][i]%P;f[1][i]=1ll*t[1][i]*t[0][i]%P;f[2][i]=1ll*t[1][i]*t[1][i]%P;t[0][i]=1ll*t[1][i]*t[1][i]%P;t[1][i]=1ll*t[1][i]*t[2][i]%P;t[2][i]=1ll*t[2][i]*t[2][i]%P;}for(int j=0;j<3;j++)NTT(f[j],-1),NTT(t[j],-1);for(int i=0;i<k-1;i++)(f[0][i+1]+=t[0][i])%P,(f[1][i+1]+=t[1][i])%P,(f[2][i+1]+=t[2][i])%P;for(int i=k;i<n;i++)f[0][i]=f[1][i]=f[2][i]=0;}for(int i=1;i<k;i++)print(g[0][i]),putchar(' ');return 0; }總結(jié)
以上是生活随笔為你收集整理的CF755G-PolandBall and Many Other Balls【倍增FFT】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为Mate60 Pro开启&ldquo
- 下一篇: OPPO 将发布全新影像战略,一加 12