【BZOJ3328】PYXFIB【矩阵快速幂】【单位根反演】【二项式定理】
傳送門
題意:
∑i=0?nk?(nik)Fik\sum_{i=0}^{\lfloor\frac nk\rfloor}\binom n{ik}F_{ik}i=0∑?kn???(ikn?)Fik?
FFF為斐波拉契數(shù)列
n≤1e18,k≤2e4,p≤1e9n\leq 1e18,k\leq2e4,p\leq1e9n≤1e18,k≤2e4,p≤1e9且為質(zhì)數(shù)且模kkk余111
顯然就是求
∑i=0n[k∣i](ni)Fi\sum_{i=0}^n[k\mid i]\binom niF_ii=0∑n?[k∣i](in?)Fi?
顯然FFF可以通過矩陣表示出來
設(shè)
A=(1110),S=(10)A=\left(\begin{matrix}1&1\\1&0\end{matrix}\right),S=\left(\begin{matrix}1\\0\end{matrix}\right)A=(11?10?),S=(10?)
那么只需要求出
∑i=0n[k∣i](ni)AiS\sum_{i=0}^n[k\mid i]\binom niA^iSi=0∑n?[k∣i](in?)AiS
相當(dāng)于求
∑i=0n[k∣i](ni)Ai\sum_{i=0}^n[k\mid i]\binom niA^ii=0∑n?[k∣i](in?)Ai
然后日常把這個幻視成二項(xiàng)式定理害得我調(diào)了兩個小時
顯然可以單位根反演
1k∑j=0k?1∑i=0n(ni)Aiωij\frac 1k\sum_{j=0}^{k-1}\sum_{i=0}^n\binom niA^i\omega^{ij}k1?j=0∑k?1?i=0∑n?(in?)Aiωij
=1k∑j=0k?1∑i=0n(ni)(Aωj)i=\frac 1k\sum_{j=0}^{k-1}\sum_{i=0}^n\binom ni(A\omega^j)^i=k1?j=0∑k?1?i=0∑n?(in?)(Aωj)i
二項(xiàng)式定理走一波
=1k∑j=0k?1(Aωj+I)n=\frac 1k\sum_{j=0}^{k-1}(A\omega^j+I)^n=k1?j=0∑k?1?(Aωj+I)n
然后就可以算了
因?yàn)?span id="ze8trgl8bvbq" class="katex--inline">p%k=1p\%k=1p%k=1,所以可以找一個原根算出ω\omegaω
復(fù)雜度O(klog?n)O(k\log n)O(klogn)
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> using namespace std; typedef long long ll; ll n; int k,MOD; 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 b) {int ans=1;while (b){if (b&1) ans=(ll)ans*a%MOD;a=(ll)a*a%MOD;b>>=1;}return ans; } int g,Wn; inline bool check(int x) {int n=x;for (int i=2;i*i<=x;i++)if (x%i==0){if (qpow(g,n/i)==1) return false;while (x%i==0) x/=i;}if (x>1&&qpow(g,n/x)==1) return false;return true; } struct mat {int e[2][2];mat(const int& x=0){e[0][0]=e[1][1]=x;e[0][1]=e[1][0]=0;}int* operator [](int i){return e[i];} }; inline int det(mat m){return dec((ll)m[0][0]*m[1][1]%MOD,(ll)m[0][1]*m[1][0]%MOD);} inline mat operator *(mat a,mat b) {mat ans;ans[0][0]=add((ll)a[0][0]*b[0][0]%MOD,(ll)a[0][1]*b[1][0]%MOD);ans[0][1]=add((ll)a[0][0]*b[0][1]%MOD,(ll)a[0][1]*b[1][1]%MOD);ans[1][0]=add((ll)a[1][0]*b[0][0]%MOD,(ll)a[1][1]*b[1][0]%MOD);ans[1][1]=add((ll)a[1][0]*b[0][1]%MOD,(ll)a[1][1]*b[1][1]%MOD); return ans; } inline mat operator +(mat a,mat b) {mat ans;ans[0][0]=add(a[0][0],b[0][0]);ans[0][1]=add(a[0][1],b[0][1]);ans[1][0]=add(a[1][0],b[1][0]);ans[1][1]=add(a[1][1],b[1][1]); return ans; } inline mat operator *(mat a,const int& t) {mat ans;ans[0][0]=(ll)a[0][0]*t%MOD;ans[0][1]=(ll)a[0][1]*t%MOD;ans[1][0]=(ll)a[1][0]*t%MOD;ans[1][1]=(ll)a[1][1]*t%MOD; return ans; } inline mat qpow(mat a,ll p) {mat ans(1);while (p){if (p&1) ans=ans*a;a=a*a;p>>=1;}return ans; } int main() {int T;scanf("%d",&T);while (T--){scanf("%lld%d%d",&n,&k,&MOD);for(g=2;!check(MOD-1);g++);Wn=qpow(g,(MOD-1)/k);mat T,sum;T[0][0]=T[0][1]=T[1][0]=1;T[1][1]=0;for (int i=0;i<k;i++,T=T*Wn) sum=sum+qpow(T+mat(1),n);sum=sum*qpow(k,MOD-2);printf("%d\n",sum[0][0]);}return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的【BZOJ3328】PYXFIB【矩阵快速幂】【单位根反演】【二项式定理】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 特斯拉 Cybertruck“禁止转售”
- 下一篇: K-D Tree学习笔记