CQU 雷神之路(DP+矩阵加速)
2016-05-26 15:32
260 查看
Time Limit: 10000 MSMemory Limit: 32768 K
雷神之路
描述
zzblack成功通关SAO,现在,等待他的将是雷神之路。雷神之路
是在x轴上的一条路。雷神在路的尽头放了无尽的宝藏。一开始,
zzblack在初始点0,每次能走一步,两步或者三步,路的尽头的点
坐标为n。雷神为了增大游戏的难度,在路上放置了m个地雷(不能
踩上去),每个地雷的坐标为,然而,zzblack破解了这个游戏,
因此他知道每个地雷的坐标。他不屑于知道能否拿到宝藏,他只想
知道有多少种方法能拿到宝藏。
输入
第一行输入一个T表示有T组样例
接下来块
每块第一行
接下来一行描述个地雷的位置
输出
输出方案数
样例输入
2
4 1
3
6 2
1 2
样例输出
3
4
思路:
还是从朴素开始:
f[i]定义为 f[i] 到达坐标i的方案数
朴素肯定是O(N)的递推:
f[i]=f[i-1]+f[i-2]+f[i-3] (如果有地雷的话,则对应f为0)
但是 N≤1e18 ,又是递推 所以很容易想到矩阵加速。
矩阵加速是在没有地雷的情况下可以直接算出f[i]
那么困难就变成了如何去掉地雷的影响
换一种方式说 地雷会产生怎样的影响
其实第i个地雷对后面的方案数造成的影响中
只有第i+1个地雷前的两个f[i-1] f[i-2]是有用的
所以我们只用算第i个地雷前面的两个个f[i-1]f[i-2]就好了。
然后f[i]=0 (是地雷嘛) 于是 f[i],f[i-1],f[i-2] 就是可以构成一个新的矩阵快速幂的起点。然后去算一下个地雷,直到算到n
复杂度 kO(m) k是矩阵快速幂的复杂度,log2(1e18)*27=60*27的样子吧= =。。
制杖思考:
一开始想了个m^2的算法用f[i]去把后面所有的地雷的方案刷一遍。。
T有500组 肯定过不了辣。。
雷神之路
描述
zzblack成功通关SAO,现在,等待他的将是雷神之路。雷神之路
是在x轴上的一条路。雷神在路的尽头放了无尽的宝藏。一开始,
zzblack在初始点0,每次能走一步,两步或者三步,路的尽头的点
坐标为n。雷神为了增大游戏的难度,在路上放置了m个地雷(不能
踩上去),每个地雷的坐标为,然而,zzblack破解了这个游戏,
因此他知道每个地雷的坐标。他不屑于知道能否拿到宝藏,他只想
知道有多少种方法能拿到宝藏。
输入
第一行输入一个T表示有T组样例
接下来块
每块第一行
接下来一行描述个地雷的位置
输出
输出方案数
样例输入
2
4 1
3
6 2
1 2
样例输出
3
4
思路:
还是从朴素开始:
f[i]定义为 f[i] 到达坐标i的方案数
朴素肯定是O(N)的递推:
f[i]=f[i-1]+f[i-2]+f[i-3] (如果有地雷的话,则对应f为0)
但是 N≤1e18 ,又是递推 所以很容易想到矩阵加速。
矩阵加速是在没有地雷的情况下可以直接算出f[i]
那么困难就变成了如何去掉地雷的影响
换一种方式说 地雷会产生怎样的影响
其实第i个地雷对后面的方案数造成的影响中
只有第i+1个地雷前的两个f[i-1] f[i-2]是有用的
所以我们只用算第i个地雷前面的两个个f[i-1]f[i-2]就好了。
然后f[i]=0 (是地雷嘛) 于是 f[i],f[i-1],f[i-2] 就是可以构成一个新的矩阵快速幂的起点。然后去算一下个地雷,直到算到n
复杂度 kO(m) k是矩阵快速幂的复杂度,log2(1e18)*27=60*27的样子吧= =。。
制杖思考:
一开始想了个m^2的算法用f[i]去把后面所有的地雷的方案刷一遍。。
T有500组 肯定过不了辣。。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define mem(array) memset(array,0,sizeof array) const int MOD=1e9+7; int T,n,m; int a[505]; long long f[505]; long long js(int x){ if(x==0) return 0; if(x==1) return 1; x--; long long D[3][3]; long long C[3][3]={1,0,0,0,1,0,0,0,1}; long long A[3][3]={1,1,0,1,0,1,1,0,0}; while(x){ if(x & 1) { for(int i=0;i<3;i++) for(int j=0;j<3;j++) { D[i][j]=0; for(int k=0;k<3;k++) //C[i][k]=A[k][j]; D[i][j]=(D[i][j]+C[i][k]*A[k][j]) % MOD; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) C[i][j]=D[i][j]; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) { D[i][j]=0; for(int k=0;k<3;k++) D[i][j]=(D[i][j]+A[i][k]*A[k][j]) %MOD; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) A[i][j]=D[i][j]; x=x>>1; } return (C[0][0]+C[1][0]) % MOD; } int main(){ freopen("in.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%d %d",&n,&m); mem(f);mem(a); //cout<<js(3)<<endl; for(int i=1;i<=m;i++) scanf("%d",&a[i]); sort(a+1,a+1+m); for(int i=1;i<=m;i++) { f[i]+=js(a[i]); for(int j=i+1;j<=m;j++) { f[j]-=f[i]*js(a[j]-a[i]) % MOD; } //cout<<f[i]<<endl; } long long ans=js(n); for(int i=1;i<=m;i++) if(n>a[i]) ans=(ans-f[i]*js(n-a[i])) % MOD; //for(int i=1;i<=n;i++) cout<<f[i]<< if(ans>0 && a[m]!=n)printf("%lld\n",ans); else cout<<0<<endl; } return 0; }
相关文章推荐
- 详解Android应用中屏幕尺寸的获取及dp和px值的转换
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- LFC1.0.0 版本发布
- Android dpi,dip,dp的概念以及屏幕适配
- Android px、dp、sp之间相互转换
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- android中像素单位dp、px、pt、sp的比较
- Android对px和dip进行尺寸转换的方法
- Android根据分辨率进行单位转换-(dp,sp转像素px)
- android 尺寸 dp,sp,px,dip,pt详解
- DP问题各种模型的状态转移方程
- POJ-1695-Magazine Delivery-dp
- nyoj-1216-整理图书-dp
- TYVJ1193 括号序列解题报告
- 对DP的一点感想
- TYVJ上一些DP的解题报告
- soj1005. Roll Playing Games
- 01背包问题