您的位置:首页 > 其它

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组 肯定过不了辣。。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp CQU