bzoj4161 Shlw loves matrixI

传送门
常系数齐次线性递推学习
学习了任意模数多项式乘除法 O ( n 2 ) O(n^2) O(n2)。除法就是手动模拟大除法。
需要的东西就是一个转移矩阵 A A A的特征多项式。
要把 A n A^{n} An看做是一个只有一项的 n n n次多项式。
然后知道初始的那几个就可以推出来了。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
typedef std::vector<int> poly;
cs int mod=1e9+7;
cs int K=2e3+5;
namespace IO{
	cs int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
	template <typename T>
	inline T get(){
		char ch=gc();T x=0,f=1;
		while(!isdigit(ch)){if(ch=='-')f=0;ch=gc();}
		while(isdigit(ch)) x=(x+(x<<2)<<1)+(ch^48),ch=gc();
		return f?x:mod-x;
	}
	inline int gi(){return get<int>();}
	inline ll gl(){return get<ll>();}
}
using IO::gi;
using IO::gl;
int n,k,h[K],a[K];
poly T;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
inline int inv(int x){return quickpow(x,mod-2);}
inline void Add(int &x,int y){x=(x+y>=mod)?x+y-mod:x+y;}
inline void Dec(int &x,int y){x=(x-y<0)?x-y+mod:x-y;}
inline void Mul(int &x,int y){x=1ll*x*y%mod;}
inline poly operator*(poly A,poly B){
	int len=A.size()+B.size()-2;
	poly C(len+1,0);
	for(int re i=0;i<A.size();++i)
		for(int re j=0;j<B.size();++j)
			Add(C[i+j],mul(A[i],B[j]));
	return C;
}
inline poly operator%(poly A,poly B){
	//len为最高次次数 
	int lenA=A.size()-1,lenB=B.size()-1,Inv=inv(B[lenB]);
	if(lenA<lenB) return A;
	for(int re i=lenA;i>=lenB;--i) if(A[i]){
		int t=mul(A[i],Inv);
		for(int re j=i;j>=i-lenB;--j)
			Dec(A[j],mul(t,B[lenB-i+j]));
	}return A.resize(lenB+1),A;
}
inline poly quickpow(poly A,int b){
	poly ret(1,1);
	for(;b;b>>=1,A=(A*A)%T) if(b&1) ret=(ret*A)%T;
	return ret;
}
int out;
int main(){
//	freopen("bzoj4161.in","r",stdin);
	n=gi(),k=gi(),T.resize(k+1),T[k]=1;
	for(int re i=1;i<=k;++i) a[i]=gi();
	for(int re i=0;i< k;++i) h[i]=gi();
	for(int re i=0;i< k;++i) T[i]=dec(0,a[k-i]);
	poly ans={0,1};ans=quickpow(ans,n);
	for(int re i=0;i<ans.size();++i) Add(out,mul(ans[i],h[i]));
	printf("%d\n",out);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值