题意:从(0,0)走到(k,0),走的过程必须在线的下面,问有多少种走法?
思路:状态转移方程 dp[i][j]=dp[i-1][j-1]+dp[i-1][j]+dp[i-1][j+1]转移,但是发现转移次数达到1e18必定会TLE.那么能不能有方法加个LOG大大降低复杂度呢? 有,用矩阵快速幂.
复杂度为O(n*log(k)*15^3)
用矩阵快速幂很典型的数据是,转移次数非常的多,但每一次转移的状态少,因为假设当前要转移n个状态,那么矩阵快速幂的复杂度就到来n^3*log(k)的复杂度,因为k非常的大,所以n一定会比较小,这样才可以用矩阵快速幂来优化.看到1e18数据的DP要考虑是否每次转移的状态少,且总共转移状态的次数异常的多,那么需要考虑用矩阵快速幂来log掉转移的总次数.
第二次做这个题,理解又加深了,开森!
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define bug cout << "bug" << endl
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int MAX_N=1e5+5;
typedef struct{
ll mat[20][20];
}matrix;
matrix matrix_mul(matrix a,matrix b,ll len){
matrix c;
memset(c.mat,0,sizeof(c.mat));
for(int i=0;i<=len;i++){
for(int j=0;j<=len;j++){
for(int k=0;k<=len;k++){
c.mat[i][j]+=(a.mat[i][k]%MOD*b.mat[k][j]%MOD);
c.mat[i][j]%=MOD;
}
}
}
return c;
}
matrix matrix_qucick_pow(matrix a,ll k,ll len){
matrix c;
memset(c.mat,0,sizeof(c.mat));
for(int i=0;i<=15;i++) c.mat[i][i]=1;
while(k){
if(k&1) c=matrix_mul(c,a,len);
a=matrix_mul(a,a,len);
k>>=1;
}
return c;
}
int main(void){
ll n,k;
cin >> n>>k;
matrix temp,a,b;
memset(a.mat,0,sizeof(a.mat));
memset(b.mat,0,sizeof(b.mat));
memset(temp.mat,0,sizeof(temp.mat));
temp.mat[0][0]=temp.mat[0][1]=1;
for(int i=1;i<=14;i++){
for(int j=i-1;j<=i+1;++j)
temp.mat[i][j]=1;
}
temp.mat[15][14]=temp.mat[15][15]=1,a.mat[0][0]=1;
// for(int i=0;i<=15;i++){
// for(int j=0;j<=15;j++) printf("%d",temp.mat[i][j]);puts("");
// }
for(int i=1;i<=n;i++){
ll l,r,y;
scanf("%lld%lld%lld",&l,&r,&y);
if(r>k) r=k;
for(int i=y+1;i<=15;++i) a.mat[i][0]=0;//删去不可能的情况,不对后面的状态转移造成影响
b=matrix_qucick_pow(temp,r-l,y);
a=matrix_mul(b,a,y);
}
cout << a.mat[0][0]%MOD<< endl;
}