很久很久都没有做过矩阵快速幂的题目了,昨天做了一个竟然丝毫想不起来。。。不由让我想复习一下。
快速幂的原理就不必多说,为了实现某些题目中的答案,答案又依赖与某些类似斐波那契数列的关系,我们就可以利用矩阵来实现 这个线性递推过程,利用快速幂的原理来缩短这个很长的线性过程。
1.先是最简单的题型
比如 a[n]= x*a[n-1] + y *a[n-2]
|a[n] |………… |x y |……….. |a[n-1] |…… |x* a [n-1] + y*a[n-2] |
|a[n-1] | =…..| 1 0 |.. *….. |a[n-2] | = ..|1*a[n-1]…………………..|
2印象有点深刻的题目,沈阳现场赛的题
http://acm.hdu.edu.cn/showproblem.php?pid=5950
F(n) = 2*F(n-2) + F(n-1) + n^4 和F(1) = a,F(2) = b;给定一个N,求F(N)等于多少?
我们可以发现这个递推里面 只有 n^4是不满足线性的
那么我们就要把这个变成线性所以要和n-1 相关联,于是n=(n-1 +1)^4
3.http://codeforces.com/contest/821/problem/E
k 1e18 可以知道,每一条线段的内(不同位置)的种数可以由长度、位置、推断出来
由于n 100 c 15,让人不由得往dp上想啊。
而且这个线段的dp肯定满足线性(从前往后)的关系。
所以我们可以枚举 每一段线段的起点,然后给这一段线段的终点添加方法数
可以得出:
+x +4x
+x +3x +10x
+x +2x +6x +16x
+x +x +3x +7x +19x
+x +2x +6x +16x
+x +3x +10x
+x +4x
我们换成矩阵的形式:
0 0 0 x 4x
0 0 x 3x 10x
0 x 2x 6x 16x
x x 3x 7x 19x
0 x 2x 6x 16x
0 0 x 3x 10x
0 0 0 x 4x
我们可以得到 dp[x][y]= dp[x-1][y-1]+dp[x-1][y]+dp[x-1][y+1]
有一个简单的方法是用线性 的累加平推过去。。。。但是肯定会TLE
所以我们用 矩。。。矩阵快速幂。 ,利用快速幂的原理可以缩短这一累乘的过程
至于矩阵 我们把所有的都看成是16*16 来做
注意把实际上无法到达的地方归零,特别是线段与线段交接时
而且特别注意的一个地方就是需要把操作矩阵相应的地方也归零,这里改了比较久
#define ll __int64
#define mod 1000000007
struct matr
{
__int64 an[20][20];
}flag,temp,ans;
void print(matr x){
for(int i=0;i<=15;i++){
for(int j=0;j<=15;j++){
printf("%I64d ",x.an[i][j]);
}
printf("\n");
}
printf("\n\n");
}
matr mul(matr a,matr b ) //注意顺序:aXb
{
matr c;
for(int i=0;i<=15;i++)
for(int j=0;j<=15;j++)
{
c.an[i][j]=0;
for(int k=0;k<=15;k++)
c.an[i][j]+=a.an[i][k]*b.an[k][j];
c.an[i][j]%=mod;
}
return c;
}
__int64 fast(__int64 n,int H)
{
temp=flag;
for(int i=0;i<H;i++){ //不能忘记吧temp相应的行数也归零啊
for(int j=0;j<=15;j++)
temp.an[i][j]=0;
}
while(n)
{
if(n%2==1)
{
ans=mul(temp,ans);
for(int j=0;j<H;j++)
ans.an[j][0]=0;
}
n/=2;
temp=mul(temp,temp);
// printf("n=%I64d\n",n);
// printf("ans=\n");
// print(ans);
// printf("temp=\n");
// print(temp);
}
return ans.an[0][0];
}
ll a[105],b[105];
int c[105];
int main(){
freopen("1.txt","r",stdin);
int n;
ll k;
scanf("%d %I64d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%I64d %I64d %d",&a[i],&b[i],&c[i]);
}
for(int i=0;i<=15;i++){
for(int j=0;j<=15;j++){
ans.an[i][j]=0;
flag.an[i][j]=0;
if(abs(j-i)<=1)
flag.an[i][j]=1;
}
}
ans.an[15][0]=1;
for(int i=1;i<=n;i++){
// printf("%dTH --line\n",i);
ll L=b[i]-a[i];
if(k <=b[i]){
L=k-a[i];
}
for(int j=0;j< 15-c[i];j++)
ans.an[j][0]=0;
fast(L,15-c[i]);
for(int j=0;j< 15-c[i];j++)
ans.an[j][0]=0;
}
printf("%I64d\n",ans.an[15][0]);
return 0;
}