Fork me on GitHub

【csp模拟赛3】bridge.cpp--矩阵加速递推

题目描述

穿越了森林,前方有一座独木桥,连接着过往和未来(连接着上一题和下一题...)。 这座桥无限长。

小 Q 在独木桥上彷徨了。他知道,他只剩下了 N 秒的时间,每一秒的时间里,他会向 左或向右移动一步。 N 秒之后,小 Q 恰在桥上某一特定位置,且他每两次经过此位置的时间间隔不会超过 M 秒。 那么问题来了,这 N 秒的时间里,小 Q 的路线总共会有多少种可能的形式。

输入

文件第一行两个正整数 N、M,如题目所描述

输出

输出一个整数,表示可能的路线数量最终模 1000000007 的结果

样例输入 1

4 2

样例输出 1

4

样例输入2

10 6

样例输出 2

184

数据规模与约定 对于 30% 的测试数据, 2 <=N<=100 ; 对于全部测试数据, 9 2 <=N <=10 , M <=N 且 M <=100 。保证 N 和 M 都是偶 数。资源限制 每个测试点空间限制 256MB,时间限制 1s。 一共 20 个测试点,满分 100 分。

思想:

    矩阵加速递推

若只考虑从最终到达的特定位置向单一方向出发,令 F(x, y)表示在一次出行内离开最终 位置 x 个单位时间时你恰好处于距最终位置 y 个单位距离的方案数。易得转移方程: F(1,1)=1,F(x,y)=F(x-1,y-1)+F(x-1,y+1). 预处理 F 数组,时间复杂度 O(M2 )。 由此可直接通过递推简便地得到答案,时间复杂度 O(NM),可通过 60%的测试数据。 利用矩阵乘法优化,可将时间复杂度优化至 O(M^3*log2N),通过全部测试数据。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define mod 1000000007
using namespace std;

int n,m;
long long f[200][200];
struct node {
	long long a[200][200];
	
}a,c;

inline node MUL(node a,node b) {
		node wfx;
		memset(wfx.a,0,sizeof(c.a));
		for(int i = 1;i <= m >> 1;i ++)
			for(int j = 1;j <= m >> 1;j ++)		
				for(int k = 1;k <= m >> 1;k ++)
					wfx.a[i][j] = (wfx.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
		return wfx;
	}		

inline void KSM(int y) {
	for( ; y ; y >>= 1,a = MUL(a,a))
		if(y & 1) c = MUL(c,a);
}


int main()
{
	#ifdef yilnr
	#else
	freopen("bridge.in","r",stdin);
	freopen("bridge.out","w",stdout);
	#endif
	scanf("%d%d",&n,&m);
	f[1][1]=1;
	for(int i=1;i<=m;i++)
	  for(int j=1;j<=(m>>1);j++)
	  {
	     f[i+1][j+1]=(f[i+1][j+1]+f[i][j])%mod;
		 f[i+1][j-1]=(f[i+1][j-1]+f[i][j])%mod;
	  }
	for(int i=1;i<=(m>>1)-1;i++)a.a[i+1][i]=1;
	for(int i=1;i<=(m>>1);i++)c.a[i][i] = 1,a.a[1][i]=(f[i<<1][0]<<1)%mod;
	KSM(n>>1);
	printf("%d",c.a[1][1]);
}

 

posted @ 2019-09-21 19:49  yelir  阅读(246)  评论(0编辑  收藏  举报