[luoguP2461] [SDOI2008]递归数列(DP + 矩阵优化)

传送门

本题主要是构造矩阵,我们只需要把那一段式子看成两个前缀和相减, 然后就直接矩阵连乘。

直接对那个k+1阶矩阵快速幂即可,注意初始化矩阵为单位矩阵,即主对角线(左上到右下)都为1其他都为0。

另外,很多量要开long long。

#include <cstdio>
#include <cstring>
#define LL long long

int k;
LL b[21], c[21], n, m, p;

struct Matrix
{
	int n, m;
	LL a[21][21];
	Matrix()
	{
		n = m = 0;
		memset(a, 0, sizeof(a));
	}
}sum, sum1, sum2, t;

inline Matrix operator * (Matrix x, Matrix y)
{
	int i, j, k;
	Matrix ans;
	ans.n = x.n;
	ans.m = y.m;
	for(i = 1; i <= x.n; i++)
		for(j = 1; j <= y.m; j++)
			for(k = 1; k <= y.n; k++)
				ans.a[i][j] = (ans.a[i][j] + x.a[i][k] * y.a[k][j]) % p;
	return ans;
}

inline Matrix operator ^ (Matrix x, LL y)
{
	int i;
	Matrix ans;
	ans.n = ans.m = k + 1;
	for(i = 1; i <= k + 1; i++) ans.a[i][i] = 1;
	for(; y; y >>= 1)
	{
		if(y & 1) ans = ans * x;
		x = x * x;
	}
	return ans;
}

int main()
{
	int i;
	scanf("%d", &k);
	for(i = 1; i <= k; i++) scanf("%lld", &b[i]);
	for(i = 1; i <= k; i++) scanf("%lld", &c[i]);
	scanf("%lld %lld %lld", &m, &n, &p);
	for(i = 1; i <= k; i++) b[i] %= p, c[i] %= p;
	sum.n = sum.m = k + 1;
	sum.a[1][1] = 1; 
	for(i = 3; i <= k + 1; i++) sum.a[i][i - 1] = 1;
	for(i = 2; i <= k + 1; i++) sum.a[1][i] = sum.a[2][i] = c[i - 1];
	t.n = k + 1;
	t.m = 1;
	for(i = 2; i <= k + 1; i++)
	{
		t.a[i][1] = b[k - i + 2];
		t.a[1][1] = (t.a[1][1] + b[i - 1]) % p;
	}
	if(n - k > 0)
		sum1 = (sum ^ (n - k)) * t;
	else for(i = 1; i <= n; i++)
		sum1.a[1][1] = (sum1.a[1][1] + b[i]) % p;
	if(m - k - 1 > 0)
		sum2 = (sum ^ (m - k - 1)) * t;
	else for(i = 1; i < m; i++)
		sum2.a[1][1] = (sum2.a[1][1] + b[i]) % p;
	printf("%lld
", ((sum1.a[1][1] - sum2.a[1][1]) % p + p) % p);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhenghaotian/p/7491950.html