Shlw loves matrixI

一、题目

点此看题
Description
给定数列 { h n } \{h_n\} k k 项,其后每一项满足
h n = a 1 h n 1 + a 2 h n 2 + . . . + a k h n k h_n = a_1*h_{n-1} + a_2*h_{n-2} + ... + a_k*h_{n-k}
其中 a 1 , a 2 . . . a k a_1,a_2...a_k 为给定数列。请计算 h ( n ) h(n) ,并将结果对 1000000007 1000000007 取模输出。
Input
第 1 行包含两个整数 n , k n,k
第 2 行包含 k 个整数 a 1 , a 2 . . . a k a_1,a_2...a_k
第 3 行包含 k 个整数 h 0 , h 1 , . . . , h k 1 h_0,h_1,...,h_{k-1}
n < = 1 0 9 ; k < = 2000 ; a b s ( h i ) < = 1 0 9 ; a b s ( a i ) < = 1 0 9 n <= 10^9;k <= 2000; abs(hi)<=10^9; abs(ai)<=10^9
Output
一行一个整数 h n m o d    1000000007 h_n \mod 1000000007

二、解法

很容易想到 O ( k 3 log n ) O(k^3\log n) 的矩阵快速幂,我们现在讲一下 O ( k 2 log n ) O(k^2\log n) 常系数齐次线性递推 方法。

首先我们构造一个特征多项式 f ( x ) = x k i = 1 k x k i × a i f(x)=x^k-\sum_{i=1}^kx^{k-i}\times a_i ,根据Cayley-Hamilton定理,有:
f ( A ) = 0 f(A)=0 A A 是我们的转移矩阵,我们把它当做自变量, 0 0 就表示全 0 0 矩阵。

A n = f ( A ) g ( A ) + R ( A ) A^n=f(A)g(A)+R(A) ,由于 f ( A ) = 0 f(A)=0 ,所以 A n = R ( A ) A^n=R(A) ,然后我们可以用类似快速幂套取模的方法算出 R ( A ) R(A) ,这一部分的时间复杂度 O ( k 2 log n ) O(k^2\log n) ,用 FFT \text{FFT} 优化可做到 O ( k log k log n ) O(k\log k\log n)

求出 R ( A ) R(A) 以后( R ( A ) R(A) k 1 k-1 次多项式),答案的向量为:
v = i = 0 k 1 r i A i v 0 = i = 0 k 1 r i v i v=\sum_{i=0}^{k-1}r_iA^iv_0=\sum_{i=0}^{k-1}r_iv_i 由于我们只需要知道 v v 的最上面一项,所以答案为 i = 0 k 1 r i h i \sum_{i=0}^{k-1} r_ih_i ,这一部分的时间复杂度 O ( k ) O(k)

#include <cstdio>
#include <cstring>
#define int long long
const int MOD = 1e9+7;
const int M = 4005;
int read()
{
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n,k,ans,f[M],h[M];
struct Matrix
{
	int a[M];
	Matrix() {memset(a,0,sizeof a);}
	int& operator [] (const int &i) {return a[i];}
	int operator [] (const int &i) const {return a[i];} 
	Matrix operator * (const Matrix &B) const
	{
		Matrix res;
		for(int i=0;i<k;i++)
			for(int j=0;j<k;j++)
				res[i+j]=(res[i+j]+a[i]*B[j])%MOD;
		for(int i=2*k-2;i>=k;res[i--]=0)
			for(int j=1;j<=k;j++)
				res[i-j]=(res[i-j]+res[i]*f[j])%MOD;
		return res; 
	}
}R;
Matrix qkpow(Matrix a,int b)
{
	Matrix res;
	res[0]=1;
	while(b>0)
	{
		if(b&1) res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
signed main()
{
	n=read();k=read();
	for(int i=1;i<=k;i++) f[i]=(read()+MOD)%MOD;
	for(int i=0;i<k;i++) h[i]=(read()+MOD)%MOD;
	if(n<k)
	{
		printf("%lld\n",h[n]);
		return 0;
	}
	R[1]=1;
	R=qkpow(R,n);
	for(int i=0;i<k;i++) ans=(ans+R[i]*h[i])%MOD;
	printf("%lld\n",ans);
}
发布了192 篇原创文章 · 获赞 12 · 访问量 3349

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/103822091