SNOI2017 礼物

题解

设前(n)个人的礼物个数和为(F_n), 那么显然$$F_n = 2 imes F_{n-1} + i^k$$
考虑矩阵快速幂
棘手的问题是:(i^k)不是可以直接用矩阵乘法可以递推的东西
由二项式定理可得:$$a^k = sum_{i = 1}{k}(a-1)i {k choose i}$$
那么我们可以给(left[ (i-1)^0; (i-1)^1;(i-1)^2; cdots; (i-1)^k; ight]) 乘上一个杨辉三角矩阵, 就能得到(left[i^0;i^1;i^2;cdots;i^k ight])
然后我们就能用矩阵快速幂算(F), 显然(Ans = F_{n-1} + i^k)
于是就做完了

注意:这题两个n相乘可能会long long溢出, 因此算(n^k)前要先给(n)取模

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>

using namespace std;


typedef long long LL;


const LL mod = 1e9 + 7;


LL power(LL a, LL n, LL mod)
{
	LL Ans = 1;
	
	while (n)
	{
		if (n & 1) Ans = Ans * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	
	return Ans;
}


LL n; int K;


struct Matrix
{
	LL a[12][12];

	Matrix() { memset(a, 0, sizeof(a)); }

	LL* operator [] (int x) { return a[x]; }
	
	friend Matrix operator * (Matrix a, Matrix b)
	{
		Matrix Ans;
		
		for (int i = 0; i <= K + 1; i++)
			for (int k = 0; k <= K + 1; k++)
				if (a[i][k])
					for (int j = 0; j <= K + 1; j++)
						(Ans[i][j] += a[i][k] * b[k][j] % mod) %= mod;
		
		return Ans;
	}
};

Matrix power(Matrix a, LL n)
{
	Matrix Ans;
	for (int i = 0; i <= K + 1; i++) Ans[i][i] = 1;
	
	while (n)
	{
		if (n & 1) Ans = Ans * a;
		a = a * a;
		n >>= 1;
	}
	
	return Ans;
}


Matrix Ans, a;


int main()
{
	Matrix A, Ans;
	
	scanf("%lld %d", &n, &K);
	
	if (n <= 2)
	{
	    LL Ans = 1;
	    for (int i = 2; i < n; i++)
	    	Ans = (2 * Ans + power(i, K, mod)) % mod;
	    Ans = (Ans + power(n, K, mod)) % mod;
	    printf("%lld
", Ans);
	    return 0;
	}
	
	A[0][0] = 1;
	for (int i = 1; i <= K; i++)
	{
		A[i][0] = 1; A[i][i] = 1;
		for (int j = 1; j < i; j++)
			A[i][j] = (A[i-1][j-1] + A[i-1][j]) % mod;
	}
	A[K+1][K+1] = 2;
	for (int i = 0; i <= K; i++)
		A[K+1][i] = A[K][i];
	
	for (int i = 0; i <= K; i++)
		Ans[i][1] = 1;
	Ans[K+1][1] = 1;
	
	Ans = power(A, n - 2) * Ans;
	
	printf("%lld
", (Ans[K+1][1] + power(n%mod, K, mod)) % mod);
	
	return 0;
}
原文地址:https://www.cnblogs.com/2016gdgzoi509/p/11148856.html