This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub tko919/library
#include "FPS/p-recursive.hpp"
#pragma once #include "FPS/samplepointshift.hpp" #include "Math/matrix.hpp" #include "Math/linearequation.hpp" template<typename T>Matrix<T> PrefixProdOfPolyMatrix(Matrix<Poly<T>>& m,ll K){ using Mat=Matrix<T>; int n=m.val.size(); int deg=1; rep(i,0,n)rep(j,0,n)chmax(deg,(int)m[i][j].size()-1); ll SQ=1; while(SQ*SQ*deg<K)SQ<<=1; T iSQ=T(SQ).inv(); vector<Mat> G(deg+1); rep(k,0,deg+1){ G[k]=Mat(n,n); rep(i,0,n)rep(j,0,n)G[k][i][j]=m[i][j].eval(SQ*k); } auto process=[&](vector<Mat>& base,T x)->vector<Mat>{ int D=base.size(); vector ret(D,Mat(n,n)); rep(i,0,n)rep(j,0,n){ vector<T> val(D); rep(k,0,D)val[k]=base[k][i][j]; auto add=SamplePointsShift<T>(val,x); rep(k,0,D)ret[k][i][j]=add[k]; } return ret; }; for(ll w=1;w<SQ;w<<=1){ auto G1=process(G,iSQ*w); auto G2=process(G,w*deg+1); auto G3=process(G,iSQ*w+w*deg+1); rep(i,0,w*deg+1)G1[i]*=G[i],G3[i]*=G2[i]; G1.insert(G1.end(),ALL(G3)); G1.pop_back(); swap(G,G1); } Mat ret(n,n); rep(i,0,n)ret[i][i]=1; ll k=0; while(k*SQ+SQ<=K)ret=G[k++]*ret; k*=SQ; while(k<K){ Mat mul(n,n); rep(i,0,n)rep(j,0,n)mul[i][j]=m[i][j].eval(k); ret=mul*ret; k++; } return ret; } // a_{n+i}*f_n(i)+...+a_i*f_0(i)=0 // {f_r}:dec order!!! template<typename T>vector<Poly<T>> FindPRecursive(vector<T>& a,int d){ int n=a.size(); int k=(n+2)/(d+2)-1; if(k<=0)return {}; int m=(d+1)*(k+1); Matrix<T> mat(m-1,m); rep(i,0,m-1)rep(j,0,k+1){ T base=1; rep(deg,0,d+1){ mat[i][(d+1)*j+deg]=a[i+j]*base; base*=(i+j); } } auto basis=LinearEquation(mat,vector<T>(m-1)).second; if(basis.val.empty())return {}; auto c=basis[0]; vector<Poly<T>> ret; for(int i=0;i*(d+1)<(int)c.size();i++){ Poly<T> add,base({T(i),T(1)}); for(int j=d;j>=0;j--){ add*=base; if(c[i*(d+1)+j]!=0)add+=c[i*(d+1)+j]; } ret.push_back(add); } while(ret.back().empty())ret.pop_back(); reverse(ALL(ret)); return ret; } template<typename T>T KthtermOfPRecursive(vector<T>& a,vector<Poly<T>>& fs,ll k){ int n=fs.size()-1; assert(int(a.size())>=n); if(k<int(a.size()))return a[k]; Matrix<Poly<T>> m(n),den(1); Matrix<T> base(n); rep(i,0,n)m[0][i]=-fs[i+1]; rep(i,1,n)m[i][i-1]=fs[0]; den[0][0]=fs[0]; rep(i,0,n)base[i][0]=a[n-1-i]; T ret=(PrefixProdOfPolyMatrix(m,k-n+1)*base)[0][0]; ret/=PrefixProdOfPolyMatrix(den,k-n+1)[0][0]; return ret; } template<typename T>T KthtermEsper(vector<T>& a,ll k){ if(k<(int)a.size())return a[k]; int n=a.size()-1; vector<Fp> b=a; b.pop_back(); for(int d=0;;d++){ if((n+2)/(d+2)<=1)break; auto fs=FindPRecursive(b,d); if(KthtermOfPRecursive(b,fs,n)==a.back()){ return KthtermOfPRecursive(a,fs,k); } } cerr<<"esper Failed"<<'\n'; assert(0); } /** * @brief P-recursive */
#line 2 "FPS/samplepointshift.hpp" template<typename T>Poly<T> SamplePointsShift(vector<T>& ys,T c,int m=-1){ ll n=ys.size()-1,C=c.v%T::get_mod(); if(m==-1)m=n+1; if(C<=n){ Poly<T> res; rep(i,C,n+1)res.push_back(ys[i]); if(int(res.size())>=m){ res.resize(m); return res; } auto add=SamplePointsShift<T>(ys,n+1,m-res.size()); for(int i=0;int(res.size())<m;i++){ res.push_back(add[i]); } return res; } if(C+m>T::get_mod()){ auto res=SamplePointsShift<T>(ys,c,T::get_mod()-c.v); auto add=SamplePointsShift<T>(ys,0,m-res.size()); rep(i,0,add.size())res.push_back(add[i]); return res; } Poly<T> A(n+1),B(m+n); rep(i,0,n+1){ A[i]=ys[i]*Fact<T>(i,1)*Fact<T>(n-i,1); if((n-i)&1)A[i]=-A[i]; } rep(i,0,m+n)B[i]=Fp(1)/(c-n+i); auto AB=A*B; vector<T> res(m); Fp base=1; rep(x,0,n+1)base*=(c-x); rep(i,0,m){ res[i]=AB[n+i]*base; base*=(c+i+1); base*=B[i]; } return res; } /** * @brief Shift of Sampling Points of Polynomial */ #line 2 "Math/matrix.hpp" template<class T>struct Matrix{ int h,w; vector<vector<T>> val; T det; Matrix(){} Matrix(int n):h(n),w(n),val(vector<vector<T>>(n,vector<T>(n))){} Matrix(int n,int m):h(n),w(m),val(vector<vector<T>>(n,vector<T>(m))){} vector<T>& operator[](const int i){return val[i];} Matrix& operator+=(const Matrix& m){ assert(h==m.h and w==m.w); rep(i,0,h)rep(j,0,w)val[i][j]+=m.val[i][j]; return *this; } Matrix& operator-=(const Matrix& m){ assert(h==m.h and w==m.w); rep(i,0,h)rep(j,0,w)val[i][j]-=m.val[i][j]; return *this; } Matrix& operator*=(const Matrix& m){ assert(w==m.h); Matrix<T> res(h,m.w); rep(i,0,h)rep(j,0,m.w)rep(k,0,w)res.val[i][j]+=val[i][k]*m.val[k][j]; *this=res; return *this; } Matrix operator+(const Matrix& m)const{return Matrix(*this)+=m;} Matrix operator-(const Matrix& m)const{return Matrix(*this)-=m;} Matrix operator*(const Matrix& m)const{return Matrix(*this)*=m;} Matrix pow(ll k){ Matrix<T> res(h,h),c=*this; rep(i,0,h)res.val[i][i]=1; while(k){if(k&1)res*=c; c*=c; k>>=1;} return res; } vector<int> gauss(int c=-1){ if(val.empty())return {}; if(c==-1)c=w; int cur=0; vector<int> res; det=1; rep(i,0,c){ if(cur==h)break; rep(j,cur,h)if(val[j][i]!=0){ swap(val[cur],val[j]); if(cur!=j)det*=-1; break; } det*=val[cur][i]; if(val[cur][i]==0)continue; rep(j,0,h)if(j!=cur){ T z=val[j][i]/val[cur][i]; rep(k,i,w)val[j][k]-=val[cur][k]*z; } res.push_back(i); cur++; } return res; } Matrix inv(){ assert(h==w); Matrix base(h,h*2),res(h,h); rep(i,0,h)rep(j,0,h)base[i][j]=val[i][j]; rep(i,0,h)base[i][h+i]=1; base.gauss(h); det=base.det; rep(i,0,h)rep(j,0,h)res[i][j]=base[i][h+j]/base[i][i]; return res; } bool operator==(const Matrix& m){ assert(h==m.h and w==m.w); rep(i,0,h)rep(j,0,w)if(val[i][j]!=m.val[i][j])return false; return true; } bool operator!=(const Matrix& m){ assert(h==m.h and w==m.w); rep(i,0,h)rep(j,0,w)if(val[i][j]==m.val[i][j])return false; return true; } friend istream& operator>>(istream& is,Matrix& m){ rep(i,0,m.h)rep(j,0,m.w)is>>m[i][j]; return is; } friend ostream& operator<<(ostream& os,Matrix& m){ rep(i,0,m.h){ rep(j,0,m.w)os<<m[i][j]<<(j==m.w-1 and i!=m.h-1?'\n':' '); } return os; } }; /** * @brief Matrix */ #line 3 "Math/linearequation.hpp" template<typename T>pair<vector<T>,Matrix<T>> LinearEquation(Matrix<T> a,vector<T> b){ int h=a.h,w=a.w; rep(i,0,h)a[i].push_back(b[i]); a.w++; vector<int> idx=a.gauss(w); rep(i,idx.size(),h)if(a[i][w]!=0)return {{},{}}; vector<T> res(w); rep(i,0,idx.size())res[idx[i]]=a[i][w]/a[i][idx[i]]; Matrix<T> d(w,h+w); rep(i,0,h)rep(j,0,w)d[j][i]=a[i][j]; rep(i,0,w)d[i][h+i]=1; int r=d.gauss(h).size(); Matrix<T> basis(w-r,w); rep(i,r,w)basis[i-r]={d[i].begin()+h,d[i].end()}; return {res,basis}; } /** * @brief Linear Equation */ #line 5 "FPS/p-recursive.hpp" template<typename T>Matrix<T> PrefixProdOfPolyMatrix(Matrix<Poly<T>>& m,ll K){ using Mat=Matrix<T>; int n=m.val.size(); int deg=1; rep(i,0,n)rep(j,0,n)chmax(deg,(int)m[i][j].size()-1); ll SQ=1; while(SQ*SQ*deg<K)SQ<<=1; T iSQ=T(SQ).inv(); vector<Mat> G(deg+1); rep(k,0,deg+1){ G[k]=Mat(n,n); rep(i,0,n)rep(j,0,n)G[k][i][j]=m[i][j].eval(SQ*k); } auto process=[&](vector<Mat>& base,T x)->vector<Mat>{ int D=base.size(); vector ret(D,Mat(n,n)); rep(i,0,n)rep(j,0,n){ vector<T> val(D); rep(k,0,D)val[k]=base[k][i][j]; auto add=SamplePointsShift<T>(val,x); rep(k,0,D)ret[k][i][j]=add[k]; } return ret; }; for(ll w=1;w<SQ;w<<=1){ auto G1=process(G,iSQ*w); auto G2=process(G,w*deg+1); auto G3=process(G,iSQ*w+w*deg+1); rep(i,0,w*deg+1)G1[i]*=G[i],G3[i]*=G2[i]; G1.insert(G1.end(),ALL(G3)); G1.pop_back(); swap(G,G1); } Mat ret(n,n); rep(i,0,n)ret[i][i]=1; ll k=0; while(k*SQ+SQ<=K)ret=G[k++]*ret; k*=SQ; while(k<K){ Mat mul(n,n); rep(i,0,n)rep(j,0,n)mul[i][j]=m[i][j].eval(k); ret=mul*ret; k++; } return ret; } // a_{n+i}*f_n(i)+...+a_i*f_0(i)=0 // {f_r}:dec order!!! template<typename T>vector<Poly<T>> FindPRecursive(vector<T>& a,int d){ int n=a.size(); int k=(n+2)/(d+2)-1; if(k<=0)return {}; int m=(d+1)*(k+1); Matrix<T> mat(m-1,m); rep(i,0,m-1)rep(j,0,k+1){ T base=1; rep(deg,0,d+1){ mat[i][(d+1)*j+deg]=a[i+j]*base; base*=(i+j); } } auto basis=LinearEquation(mat,vector<T>(m-1)).second; if(basis.val.empty())return {}; auto c=basis[0]; vector<Poly<T>> ret; for(int i=0;i*(d+1)<(int)c.size();i++){ Poly<T> add,base({T(i),T(1)}); for(int j=d;j>=0;j--){ add*=base; if(c[i*(d+1)+j]!=0)add+=c[i*(d+1)+j]; } ret.push_back(add); } while(ret.back().empty())ret.pop_back(); reverse(ALL(ret)); return ret; } template<typename T>T KthtermOfPRecursive(vector<T>& a,vector<Poly<T>>& fs,ll k){ int n=fs.size()-1; assert(int(a.size())>=n); if(k<int(a.size()))return a[k]; Matrix<Poly<T>> m(n),den(1); Matrix<T> base(n); rep(i,0,n)m[0][i]=-fs[i+1]; rep(i,1,n)m[i][i-1]=fs[0]; den[0][0]=fs[0]; rep(i,0,n)base[i][0]=a[n-1-i]; T ret=(PrefixProdOfPolyMatrix(m,k-n+1)*base)[0][0]; ret/=PrefixProdOfPolyMatrix(den,k-n+1)[0][0]; return ret; } template<typename T>T KthtermEsper(vector<T>& a,ll k){ if(k<(int)a.size())return a[k]; int n=a.size()-1; vector<Fp> b=a; b.pop_back(); for(int d=0;;d++){ if((n+2)/(d+2)<=1)break; auto fs=FindPRecursive(b,d); if(KthtermOfPRecursive(b,fs,n)==a.back()){ return KthtermOfPRecursive(a,fs,k); } } cerr<<"esper Failed"<<'\n'; assert(0); } /** * @brief P-recursive */