矩阵快速幂的复习。。。

来源:互联网 发布:latex windows 编辑:程序博客网 时间:2024/06/07 02:59

很久很久都没有做过矩阵快速幂的题目了,昨天做了一个竟然丝毫想不起来。。。不由让我想复习一下。

快速幂的原理就不必多说,为了实现某些题目中的答案,答案又依赖与某些类似斐波那契数列的关系,我们就可以利用矩阵来实现 这个线性递推过程,利用快速幂的原理来缩短这个很长的线性过程。

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 1000000007struct 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;}