zoukankan      html  css  js  c++  java
  • 【BZOJ】【3240】【NOI2013】矩阵游戏

    十进制快速幂+矩阵乘法+常数优化


      听说这题还可以强行算出来递推式……然后乘乘除除算出来……

      然而蒟蒻选择了一个比较暴力的做法= =

      我们发现这个递推的过程是线性的,所以可以用矩阵乘法来表示,$x=a*x+b$这样一个递推式我们可以这样表示:$$egin{bmatrix} x& 1 end{bmatrix} * egin{bmatrix} a& 0 \ b& 1 end{bmatrix} $$

      那么我们可以令$s_1$表示×a+b,$s_2$表示×c+d,那么我们有$$ans=v * ( ({s_1}^{n-1}*s_2)^{m-1} * {s_1}^{n-1} )$$

      然而直接算我给TLE了……

      

      下面说一下常数优化:

      我们注意到矩阵乘法的时候有:$$egin{bmatrix} a& 0 \ b& 1 end{bmatrix} * egin{bmatrix} c& 0 \ d& 1 end{bmatrix} = egin{bmatrix} a*c& 0 \ a*d+b& 1 end{bmatrix}$$

      也就是说:第二列的0和1是一直不动的……那么我们可以将大部分$O(n^3)$的矩阵乘法过程优化到$O(n^2)$。

      这里我们${s_1}^{n-1}$出现了两次,那么我们可以用一个中间变量先存下来,可以减少一次运算(毕竟整个算法的主要部分就是在算这几个power)

     1 /**************************************************************
     2     Problem: 3240
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:7980 ms
     7     Memory:3232 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 3240
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=1e6+10,INF=~0u>>2,P=1e9+7;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31  
    32 struct Matrix{
    33     int v[2][2];
    34     Matrix(int x=0){F(i,0,1)F(j,0,1)if(i==j)v[i][j]=x;else v[i][j]=0;}
    35     int* operator [] (int x){return v[x];}
    36 }s1,s2,v;
    37 inline Matrix operator * (Matrix a,Matrix b){
    38     Matrix c;
    39     if (a[0][1]==0 && a[1][1]==1 && b[0][1]==0 && b[1][1]==1){
    40         c[0][0]=(LL)a[0][0]*b[0][0]%P;
    41         c[0][1]=0;
    42         c[1][0]=((LL)a[0][0]*b[1][0]+(LL)a[1][0])%P;
    43         c[1][1]=1;
    44         return c;
    45     }
    46     F(k,0,1) F(i,0,1) F(j,0,1)
    47         c[i][j]=((LL)c[i][j]+(LL)a[i][k]*b[k][j]%P)%P;
    48     return c;
    49 }
    50 inline Matrix Pow(Matrix a,int b){
    51     Matrix c(1);
    52     F(i,1,b) c=c*a;
    53     return c;
    54 }
    55 inline Matrix Power(Matrix a,char* s){
    56     Matrix r(1); int l=strlen(s);
    57     D(i,l-1,0){
    58         if (s[i]-'0') r=r*Pow(a,s[i]-'0');
    59         a=Pow(a,10);
    60     }
    61     return r;
    62 }
    63 char n[N],m[N];
    64 int main(){
    65 #ifndef ONLINE_JUDGE
    66     freopen("3240.in","r",stdin);
    67     freopen("3240.out","w",stdout);
    68 #endif
    69     scanf("%s",n); scanf("%s",m);
    70     int l1=strlen(n)-1;
    71     while(n[l1]=='0') n[l1--]='9';
    72     n[l1]--;
    73     l1=strlen(m)-1;
    74     while(m[l1]=='0') m[l1--]='9';
    75     m[l1]--;
    76 //  printf("%s %s
    ",n,m);
    77     int a,b,c,d;
    78     a=getint(); b=getint(); c=getint(); d=getint();
    79     v[0][0]=v[0][1]=1; v[1][0]=v[1][1]=0;
    80     s1[0][0]=a; s1[0][1]=0; s1[1][0]=b; s1[1][1]=1;
    81     s2[0][0]=c; s2[0][1]=0; s2[1][0]=d; s2[1][1]=1;
    82     Matrix s3=Power(s1,m);
    83     v=v*(Power(s3*s2,n)*s3);
    84     printf("%d
    ",v[0][0]);
    85     return 0;
    86 }
    View Code

    3240: [Noi2013]矩阵游戏

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 890  Solved: 390
    [Submit][Status][Discuss]

    Description

    婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式:

    F[1][1]=1
    F[i,j]=a*F[i][j-1]+b (j!=1)
    F[i,1]=c*F[i-1][m]+d (i!=1)
    递推式中a,b,c,d都是给定的常数。

    现在婷婷想知道F[n][m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F[n][m]除以1,000,000,007的余数。

    Input

    一行有六个整数n,m,a,b,c,d。意义如题所述

    Output

    包含一个整数,表示F[n][m]除以1,000,000,007的余数

    Sample Input

    3 4 1 3 2 6

    Sample Output

    85

    HINT

    样例中的矩阵为:

    1 4 7 10

    26 29 32 35

    76 79 82 85



    1<=N,M<=10^1000 000,a<=a,b,c,d<=10^9

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    Linux下基于PAM机制的USB Key的制作
    IP-route管理路由
    Linux下CPU主板监控工具lm_sensors
    两个网卡隔离方法
    关机后内存的数据是怎么丢失的呢?
    6.0 移动端页面布局
    CyberPlayer 使用教程
    5.10 HTML5 音频和视频
    让Ecshop网店系统用户自动登陆
    設定 Bootstrap/SASS/Bower/gulp (Windows平台)
  • 原文地址:https://www.cnblogs.com/Tunix/p/4558617.html
Copyright © 2011-2022 走看看