zoukankan      html  css  js  c++  java
  • (十进制高速幂+矩阵优化)BZOJ 3240 3240: [Noi2013]矩阵游戏

    题目链接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=3240

    3240: [Noi2013]矩阵游戏

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 317  Solved: 152
    [Submit][Status]

    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



    Source



    解题思路:

    十进制高速幂

    须要优化常数,能够把矩阵优化到仅仅保存两个数。每次矩阵乘法时,仅仅需计算两次乘法即可了。大大加快了速度。

    显然最后结果为A^m(BA^mF)^n 当中A(a,b,0,1)  B(c,d,0,1) F(1,0,0,1)

    保存一个v1,v2. 矩阵乘法时 c.v1=a.v1*b.v1 c.v2=a.v1*b.v2+a.v2    (ta*(1,2)+tb=(ta*1,ta*2+tb))

    代码:

    //#include<CSpreadSheet.h>
    
    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<sstream>
    #include<cstdlib>
    #include<string>
    #include<string.h>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #include<ctime>
    #include<bitset>
    #include<cmath>
    #define eps 1e-6
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    //#define ll __int64
    #define ll long long
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #define MM 1000000007
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    #define Maxn 1100000
    
    char s1[Maxn],s2[Maxn];
    ll a,b,c,d;
    
    void sub(char * cur)
    {
        int len=strlen(cur);
    
        len--;
        if(cur[len]!='0')
        {
            cur[len]=cur[len]-1;
            return ;
        }
        cur[len]='9';
        len--;
    
        while(len>=0&&cur[len]=='0')
        {
            cur[len]='9';
            len--;
        }
        cur[len]=cur[len]-1;
    }
    struct Mar
    {
        ll v1,v2;
    
        void init(ll a,ll b)
        {
            v1=a;
            v2=b;
        }
        friend struct Mar operator * (const struct Mar &a,const struct Mar &b)
        {
    
            Mar c;
    
            c.v1=(a.v1*b.v1)%MM;
            c.v2=(a.v1*b.v2+a.v2)%MM;
    
            return c;
    
    
        }
    
    };
    
    
    Mar Pow(Mar aa,ll bb)
    {
        Mar c;
        c.init(1,0);
        //c.s[1][1]=1,c.s[2][2]=1;
    
        while(bb)
        {
            if(bb&1)
                c=aa*c;
            bb>>=1;
            aa=aa*aa;
        }
        return c;
    }
    Mar T_Pow(Mar aa,char * cur)
    {
        Mar res;
        res.init(1,0);
    
        int i=strlen(cur)-1;
        int j=0;
        while(cur[j]=='0')
            j++;
        while(i>=j)
        {
            res=Pow(aa,cur[i]-'0')*res;
            aa=Pow(aa,10);
            i--;
        }
        return res;
    }
    
    int main()
    {
       //freopen("in.txt","r",stdin);
       //freopen("out.txt","w",stdout);
    
       while(~scanf("%s%s",s1,s2))
       {
           scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
           sub(s1);
           //printf("%s
    ",s1);
           sub(s2);
           //printf("%s
    ",s2);
          // ll n=cal(s1),m=cal(s2);
    
           Mar A;
           A.init(a,b);
           //A.s[1][1]=a,A.s[1][2]=b,A.s[2][2]=1;
           Mar B;
           B.init(c,d);
           //B.s[1][1]=c,B.s[1][2]=d,B.s[2][2]=1;
    
           Mar C=T_Pow(A,s2);
           Mar D=B*C;
           D=T_Pow(D,s1);
           D=C*D;
    
           printf("%lld
    ",(D.v1+D.v2)%MM);
    
       }
       return 0;
    }
    
    
    
    
    


    解题思路:

    能够暴力推出公式.费马小定理不适合于矩阵的次幂,a=c=1时,退化成等差数列。需特判,其余等比数列。这题这样做有问题。矩阵的次幂不能用费马小定理来降次,仅仅是这题有点特殊。

    代码:

    //#include<CSpreadSheet.h>
    
    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<sstream>
    #include<cstdlib>
    #include<string>
    #include<string.h>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #include<ctime>
    #include<bitset>
    #include<cmath>
    #define eps 1e-6
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    //#define ll __int64
    #define ll long long
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #define MM 1000000007
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    #define Maxn 1100000
    
    char s1[Maxn],s2[Maxn];
    ll a,b,c,d,M;
    
    ll cal(char * s)
    {
        ll res=0;
        int i=0;
    
        while(s[i])
        {
            res=(res*10+s[i]-'0')%M;
            i++;
        }
        return (res-1+M)%M;
    
    }
    
    struct Mar
    {
        ll s[3][3];
        int row,col;
    
        void init(int a,int b)
        {
            row=a,col=b;
            memset(s,0,sizeof(s));
        }
    
    };
    struct Mar operator * (const struct Mar &a,const struct Mar &b)
    {
        Mar c;
    
        c.init(a.row,b.col);
    
        for(int k=1;k<=a.col;k++)
        {
            for(int i=1;i<=a.row;i++)
            {
                if(!a.s[i][k])
                    continue;
                for(int j=1;j<=b.col;j++)
                {
                    if(!b.s[k][j])
                        continue;
                    c.s[i][j]=(c.s[i][j]+a.s[i][k]*b.s[k][j])%MM;
                }
            }
        }
        return c;
    
    }
    
    Mar Pow(Mar aa,ll bb)
    {
        Mar c;
        c.init(aa.row,aa.col);
        c.s[1][1]=1,c.s[2][2]=1;
    
        while(bb)
        {
            if(bb&1)
                c=aa*c;
            bb>>=1;
            aa=aa*aa;
        }
        return c;
    }
    
    int main()
    {
       //freopen("in.txt","r",stdin);
       //freopen("out.txt","w",stdout);
    
       while(~scanf("%s%s",s1,s2))
       {
           scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    
           if(a==1&&c==1)
                M=MM;
           else
                M=MM-1;
          // M=MM-1;
           ll n=cal(s1),m=cal(s2);
    
           Mar A;
           A.init(2,2);
           A.s[1][1]=a,A.s[1][2]=b,A.s[2][2]=1;
    
           Mar B;
           B.init(2,2);
           B.s[1][1]=c,B.s[1][2]=d,B.s[2][2]=1;
    
           Mar C=Pow(A,m);
           Mar D=B*C;
           D=Pow(D,n);
           D=C*D;
    
           printf("%lld
    ",(D.s[1][1]+D.s[1][2])%MM);
    
       }
       return 0;
    }
    
    
    
    



  • 相关阅读:
    ubuntu:activate root
    C/C++ char* arr与char arr[]的区别(反汇编解析)
    [转]关于编写Nios II的延时函数的一点心得
    [转]Xilinx Vivado的使用详细介绍(1):创建工程、编写代码、行为仿真、Testbench
    [转]Vivado中IP的使用方法
    [转]Vivado IP核生成设置
    [转]VHDL中数据类型转换与移位(STD_LOGIC_ARITH与NUMERIC_STD)
    [转]Vivado与SDK的联合调试方法-使用ILA
    [转]Vivado中ILA的使用
    [转]vivado硬件调试——mark_debug
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5204405.html
Copyright © 2011-2022 走看看