(十进制快速幂+矩阵优化)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



(十进制快速幂+矩阵优化)BZOJ 3240 3240: [Noi2013]矩阵游戏_第1张图片

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\n",s1);
       sub(s2);
       //printf("%s\n",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\n",(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\n",(D.s[1][1]+D.s[1][2])%MM);

   }
   return 0;
}






你可能感兴趣的:((十进制快速幂+矩阵优化)BZOJ 3240 3240: [Noi2013]矩阵游戏)