HDU 4990 Reading Comprehension ( 矩阵快速幂 + 找规律 )

 

HDU 4990 Reading Comprehension ( 矩阵快速幂 )

 

 

题意:

给出了一段代码,

输入代码中的n,m

按照要求输出与上面代码一样的输出结果。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include<iostream> #include <cstring> #include <cmath> #include <algorithm> #include<vector> const int MAX=100000*2; const int INF=1e9; int main() { int n,m,ans,i; while(scanf("%d%d",&n,&m)!=EOF) { ans=0; for(i=1;i<=n;i++) { if(i&1)ans=(ans*2+1)%m; else ans=ans*2%m; } printf("%d\n",ans); } return 0; }

 

分析:



可以直接运行一下程序看看,很容易找到规律

ans 初始为 0

i为偶数 ans = (ans*2)%m

i为奇数 ans = (ans*2 + 1)%m



想办法找到矩阵。。

我自己构造了一个矩阵,方法类似于233 matrix那题



0  1  0

0  2  1

-2 1  0

 

HDU 4990 Reading Comprehension ( 矩阵快速幂 + 找规律 )

 

代码:
#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <iostream>

using namespace std;

#define MAX_SIZE 3

#define CLR( a, b ) memset( a, b, sizeof(a) )



typedef __int64 LL;

LL m, n;



struct Mat

{

    LL mat[MAX_SIZE][MAX_SIZE];

    

    Mat()

    {

        CLR( mat, 0 );

    }    

    Mat operator*( const Mat &b )const

    {

        Mat c;

        for( int k = 0; k < 3; ++k )

            for( int i = 0; i < 3; ++i )    if( mat[i][k] )

                for( int j = 0; j < 3; ++j )

                    c.mat[i][j] = ( c.mat[i][j] + mat[i][k] * b.mat[k][j] ) % m;     

        return c;

    }

    void debug()

    {

        for( int i = 0; i < 3; ++i )

        {

            for( int j = 0; j < 3; ++j )

            {

                if( j != 0 )    putchar( ' ' );

                printf( "%lld", mat[i][j] );

            }

            putchar( '\n' );

        }

    }

};



Mat fast_mod( Mat a, LL b )

{

    Mat res;

    res.mat[0][0] = res.mat[1][1] = res.mat[2][2] = 1;

    while( b )

    {

        if( b & 1 )    res = res * a;

        a = a * a;

        b >>= 1;

    }

    return res;

}



void Orz()

{

    Mat c;

    c.mat[0][1] = c.mat[1][2] = c.mat[2][1] = 1;

    c.mat[1][1] = 2;

    c.mat[2][0] = -2;

    //c.debug();

    LL M[3];

    M[0] = 1, M[1] = 2, M[2] = 1;

    

    while( ~scanf( "%I64d %I64d", &n, &m ) )

    {

        if( n == 1 )     printf( "%I64d\n", 1 % m );

        else if( n == 2) printf( "%I64d\n", 2 % m );

        else

        {

            Mat res = fast_mod( c, n - 2 );    

    //        res.debug();

            LL ans = ( res.mat[1][0] * M[0] + res.mat[1][1] * M[1] + res.mat[1][2] * M[2] ) % m;

            printf( "%I64d\n", ans );

        }    

    }

}



int main()

{

    Orz();    

    return 0;

}
代码君

 

查看别人的题解:

矩阵找的和我不一样,究其原因。他们直接找到了通项公式,,,,,我晕。

打个小表查看 

1, 2, 5, 10, 21, 42



5  = 2*1 + 2  + 1

10 = 2*2 + 5  + 1

21 = 2*5 + 10 +1   

   

通项公式就是 f3= 2*f1 + f2 + 1
PS:仔细想想我推出的那个矩阵,也是用到了这个关系的,不然怎么可能会对。。。
#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <iostream>

using namespace std;

#define MAX_SIZE 3

#define CLR( a, b ) memset( a, b, sizeof(a) )



typedef __int64 LL;

LL m, n;



struct Mat

{

    LL mat[MAX_SIZE][MAX_SIZE];

    

    Mat()

    {

        CLR( mat, 0 );

    }    

    Mat operator*( const Mat &b )const

    {

        Mat c;

        for( int k = 0; k < 3; ++k )

            for( int i = 0; i < 3; ++i )    if( mat[i][k] )

                for( int j = 0; j < 3; ++j )

                    c.mat[i][j] = ( c.mat[i][j] + mat[i][k] * b.mat[k][j] ) % m;     

        return c;

    }

    void debug()

    {

        for( int i = 0; i < 3; ++i )

        {

            for( int j = 0; j < 3; ++j )

            {

                if( j != 0 )    putchar( ' ' );

                printf( "%lld", mat[i][j] );

            }

            putchar( '\n' );

        }

    }

};



Mat fast_mod( Mat a, LL b )

{

    Mat res;

    res.mat[0][0] = res.mat[1][1] = res.mat[2][2] = 1;

    while( b )

    {

        if( b & 1 )    res = res * a;

        a = a * a;

        b >>= 1;

    }

    return res;

}



void Orz()

{

    Mat c;

    c.mat[0][1] = 2;

    c.mat[1][0] = c.mat[1][1] = c.mat[2][1] = c.mat[2][2] = 1;

    //c.debug();

    Mat b;

    b.mat[0][0] = 1, b.mat[0][1] = 2, b.mat[0][2] = 1;

    

    while( ~scanf( "%I64d %I64d", &n, &m ) )

    {

        if( n == 1 )     printf( "%I64d\n", 1 % m );

        else if( n == 2) printf( "%I64d\n", 2 % m );

        else

        {

            Mat res = fast_mod( c, n - 2 );    

    //        res.debug();

            res = b * res;

            printf( "%I64d\n", res.mat[0][1] );

        }    

    }

}



int main()

{

    Orz();    

    return 0;

}
代码君

 

 

总结:

这题1A本来是没有问题,,但是自己在特盘的时候傻了



正确应该是这样,是需要进行mod运算的

if( n == 1 )     printf( "%I64d\n", 1 % m );

else if( n == 2) printf( "%I64d\n", 2 % m );

我这里居然想当然用了

if( n == 1 )     puts( "1" );

else if( n == 2)  puts( "2" );



浪费了好多次WA才明白。。。

 

你可能感兴趣的:(reading)