Codeforces 392C Yet Another Number Sequence

3 篇文章 0 订阅
2 篇文章 0 订阅

题目链接:http://codeforces.com/problemset/problem/392/C

题目简述:

F1 = 1, F2 = 2, Fi = Fi - 1 + Fi - 2 (i > 2).

We'll define a new number sequence Ai(k) by the formula:

Ai(k) = Fi × ik (i ≥ 1).

In this problem, your task is to calculate the following sum: A1(k) + A2(k) + ... + An(k). The answer can be very large, so print it modulo1000000007 (109 + 7).

 (1 ≤ n ≤ 1017; 1 ≤ k ≤ 40).


Then:

挺有意思的题。。。挺有意思。。真有意思。
如果我做这道题之前就写过什么矩阵递推总结。
这题很有启发性啊,就是因为这个题才让我有写那个东西的想法。

一看肯定是矩阵,然后呢?然后就真的没有然后了。


怎么构造转移矩阵。初始矩阵又是什么。根本不知道。

从头开始想吧, 如果有了AiK的递推,那求和肯定就不是问题(总结里写过)。
矩阵可以解决线性递推。
那么我们肯定要先把Ai(k)这个式子变成一个递推式,而不是通项。! 这是本题的关键啊!!!(当然只是我以为)
下面就考虑如何变形:

A_{i}(K)\\
=F_{i}*i^K \\
=(F_{i-1}+F_{i-2})*i^K\\
=F_{i-1}*i^K+F_{i-2}*i^K\\
=F_{i-1}*[(i-1)+1]^K+F_{i-2}*[(i-2)+2]^K\\
=\sum_{j=0}^{K} {\binom{K}{j}*F_{i-1}*(i-1)^j}+\sum_{j=0}^{K} {\binom{K}{j}*2^{K-j}*F_{i-2}*(i-2)^j}\\
=\sum_{j=0}^{K} {\binom{K}{j}*A_{i-1}(j)}+\sum_{j=0}^{K} {\binom{K}{j}*2^{K-j}*A_{i-2}(j)}\\

然后我们就得到了一个 A i ( k ) 的递推式。
考虑怎么建立初始矩阵:

这样的矩阵才能记录完信息,
我最开始竟然建成两行,是不是沙茶。 两行怎么推。
转移矩阵是2*K+1的,
系数在上面的式子已经很清楚了,都是些组合数或者组合数乘2的幂。
不方便打出来啊。。太难打了。。

然后就是代码实现的问题了。。
像我这样建立矩阵,恶心到死。
哎,反正建立矩阵超级恶心啊,后面都不是事儿了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
typedef long long LL;
const LL MOD=1000000007;
const int MAX_K=45;
struct Matrix{
	LL a[MAX_K*2][MAX_K*2],n,m;
	Matrix(int _n = 0,int _m = 0):n(_n),m(_m){rep(i,1,n)rep(j,1,m) a[i][j]=0;}
	void dw(int _n,int _m){n=_n,m=_m;rep(i,1,n)rep(j,1,m) a[i][j]=(i==j?1:0);}
	LL& operator ()(int i,int j){return a[i][j];}
	void print(){
		rep(i,1,n) rep(j,1,m) printf("%I64d%c",a[i][j],j==m?'\n':' ');
		}
};
Matrix operator *(Matrix a,Matrix b){
	Matrix res(a.n,b.m);
	rep(i,1,a.n) rep(j,1,b.m) rep(k,1,a.m)
		(res(i,j)+=a(i,k)*b(k,j))%=MOD;
	return res;
}
Matrix operator ^(Matrix a,LL x){
	Matrix res;res.dw(a.n,a.m);
	for (;x;a=a*a,x>>=1)
		if (x&1) res=res*a;
	return res;
}
LL pow2[MAX_K*2];
LL c[MAX_K*2][MAX_K*2];
void getC(int x){
	c[0][0]=1;pow2[0]=1;
	rep(i,1,x){
		c[i][0]=1;pow2[i]=(pow2[i-1]*2)%MOD;
		rep(j,1,i) c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
		}
}
LL n,k;
int main(){
	scanf("%I64d%I64d",&n,&k);
	getC(k);
	Matrix a(1,2*k+3),dp(2*k+3,2*k+3);
//	rep(i,1,k+1) a(1,i)=1;
	rep(i,1,k+1) a(1,i)=2*pow2[k-i+1];
	rep(i,k+2,2*k+2) a(1,i)=1;
	a(1,2*k+3)=1;
	rep(i,1,k+1) rep(j,1,i) dp(i,j)=c[k-j+1][k-i+1];
	rep(i,k+2,2*k+2) rep(j,1,i-(k+1))
		dp(i,j)=pow2[i-(k+1)-1-(j-1)]*c[k-j+1][k-(i-(k+1))+1]%MOD;
	//rep(i,1,k+1) rep(j,1,k-(i-1)+1) dp(i,j)=c[k-j+1][i-1];
	//rep(i,k+2,2*k+2) rep(j,1,k-(i-(k+1)-1)+1)
	//	dp(i,j)=(pow2[k-(i-(k+1)-1)-(j-1)]*c[k-j+1][i-(k+1)-1])%MOD;
	rep(i,k+2,2*k+2) dp(i-(k+1),i)=1;
	dp(1,2*k+3)=dp(2*k+3,2*k+3)=1;
//	dp.print();
//	a.print();
	a=a*(dp^(n-1));
//	a.print();
	printf("%I64d\n",a(1,2*k+3));
}


总结下吧:

矩阵递推,当然要求出递推式。。然后问题就迎刃而解了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值