Luogu P4723 模板常系数齐次线性递推

Posted wwwsfff

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P4723 模板常系数齐次线性递推相关的知识,希望对你有一定的参考价值。

看了一下午的特征多项式,仍然不晓得特征多项式
所以看了BJ大神的博客后恍然大悟
答案相当于求\\(x^n\\),发现可以写作\\(x^n-a_1 x^{n-1}-a_2 x^{n-2}\\cdots\\)可以像小学生一样尝试消元,这便是多项式取模
最后乘起来加起来即可
EI队长的优化估计这辈子都不会去填坑了

#include<bits/stdc++.h>
#define ll long long
const int p=998244353,G=3;
using namespace std;

const int N=4e5+5;
int n,m,gi,f[N],g[N],a[N],h[N],len,rf[N];
int mo(int x) {
	return x>=p?x-p:x;
}
int ksm(ll a,int b) {
	ll ret=1;
	while(b) {
		if(b&1) ret=ret*a%p;
		a=a*a%p,b>>=1;
	}
	return ret;
}
void ntt(int *a,int len,int op) {
	static int R[N];
	for(int i=0;i<len;i++) {
		R[i]=(R[i>>1]>>1);
		if(i&1) R[i]|=(len>>1);
		if(R[i]>i) swap(a[R[i]],a[i]);
	}
	for(int i=1;i<len;i<<=1){
		int Wn=ksm(op==1?G:gi,(p-1)/(i<<1));
		for(int j=0;j<len;j+=(i<<1)) {
			ll w=1;
			for(int k=j;k<j+i;k++) {
				int t=w*a[k+i]%p;
				a[k+i]=mo(a[k]+p-t);
				a[k]=mo(a[k]+t);
				w=w*Wn%p;
			}
		}
	}	
	if(op==-1) {
		int t=ksm(len,p-2);
		for(int i=0;i<len;i++) a[i]=(ll)a[i]*t%p;
	}
}
void getinv(int *a,int len,int *b) {
	static int c[N];
	if(len==1) {
		b[0]=ksm(a[0],p-2);
		b[1]=0;
		return;
	}
	getinv(a,len>>1,b);
	for(int i=0;i<len;i++) c[i]=a[i];
	fill(b+len,b+(len<<1),0);
	fill(c+len,c+(len<<1),0);
	ntt(c,len<<1,1),ntt(b,len<<1,1);
	for(int i=0;i<(len<<1);i++) b[i]=(ll)b[i]*(p+2-(ll)c[i]*b[i]%p)%p;
	ntt(b,len<<1,-1);
	fill(b+len,b+(len<<1),0);
}
void mod(int *a) {
	static int t[N],q[N];
	int l=(m<<1)-2; while(a[l]==0) --l; l++;
	if(l<=m) return;
	memcpy(t,a,sizeof(t));
	reverse(t,t+l);
	fill(t+l-m,t+l,0);
	ntt(t,len<<1,1);
	for(int i=0;i<(len<<1);i++) q[i]=(ll)t[i]*rf[i]%p;
	ntt(q,len<<1,-1);
	fill(q+l-m,q+(len<<1),0);
	reverse(q,q+l-m);
	ntt(q,len<<1,1);
	for(int i=0;i<(len<<1);i++) q[i]=(ll)q[i]*f[i]%p;
	ntt(q,len<<1,-1);
	for(int i=0;i<m;i++) a[i]=mo(a[i]+p-q[i]);
	fill(a+m,a+l,0);
}
void Ksm(int* A,int b,int *C) {
	C[0]=1;
	while(b){
		if(b&1) {
			ntt(A,len<<1,1),ntt(C,len<<1,1);
			for(int i=0;i<(len<<1);i++) {
				C[i]=(ll)C[i]*A[i]%p;
				A[i]=(ll)A[i]*A[i]%p;
			}
			ntt(A,len<<1,-1),ntt(C,len<<1,-1);
			mod(A),mod(C);
		} else {
			ntt(A,len<<1,1);
			for(int i=0;i<(len<<1);i++) A[i]=(ll)A[i]*A[i]%p;
			ntt(A,len<<1,-1);
			mod(A);
		}
		b>>=1;
	}
}

int tmp[N];
int main() {
	gi=ksm(G,p-2);
	scanf("%d%d",&n,&m);
	for(len=1;len<=m;len<<=1);
	for(int i=1;i<=m;i++) {
		scanf("%d",&f[m-i]),f[m-i]=mo(p-f[m-i]%p);
	}
	f[m]=1;
	memcpy(rf,f,sizeof(f));
	ntt(f,len<<1,1);
	reverse(rf,rf+m+1);
	memcpy(tmp,rf,sizeof(rf));
	getinv(tmp,len,rf);
	ntt(rf,len<<1,1);
	for(int i=0;i<m;i++) {
		scanf("%d",&a[i]),a[i]=mo(a[i]%p+p);
	}
	g[1]=1; 
	Ksm(g,n,h);
	int ans=0;
	for(int i=0;i<m;i++) ans=(ans+(ll)a[i]*h[i])%p;
	cout<<ans<<endl;
	return 0;
}

以上是关于Luogu P4723 模板常系数齐次线性递推的主要内容,如果未能解决你的问题,请参考以下文章

常系数齐次线性递推

特征多项式 与 常系数线性齐次递推

特征多项式 与 常系数线性齐次递推

「常系数齐次线性递推」——矩阵快速幂的优化

特征多项式

[模板] 常系数线性递推