hdu 4291 A Short problem(矩阵+取模循环节)

A Short problem

                                                         Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1785    Accepted Submission(s): 651

Problem Description

  According to a research, VIM users tend to have shorter fingers, compared with Emacs users.

  Hence they prefer problems short, too. Here is a short one:

  Given n (1 <= n <= 1018), You should solve for

g(g(g(n))) mod 109 + 7

  where

g(n) = 3g(n - 1) + g(n - 2)

g(1) = 1

g(0) = 0

Input

  There are several test cases. For each test case there is an integer n in a single line.

  Please process until EOF (End Of File).

Output

  For each test case, please print a single line with a integer, the corresponding answer to this case.

Sample Input

0
1
2

Sample Output

0
1
42837

矩阵很容易构造

矩阵A

1   0

0   0

递推矩阵B

3   1

1   0

g(n)=A*B^(n-1)的第1行第1列。

现在是一个多重函数在最外层取模,n为10^18,当到最外层取模肯定不可以,这时候就要寻找循环节了。首先是最

外层的模,通过暴力判循环节

long long x3, x1=0,x2=1;
     long long temp=1000000007;
     for(long long i=2;;i++)
     {
         x3=(3*x2+x1)%temp;
         if(x3==1&&x2==0)
         {
             printf("%I64d\n",i-1);
             break;
         }
         x1=x2;
         x2=x3;
     }

求出第2层队222222224 取模,同理第3层对183120取模。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct matrix
{
    long long ma[3][3];
};
long long mod[3];
matrix multi(matrix x,matrix y,long long m)
{
    matrix ans;
    memset(ans.ma,0,sizeof(ans.ma));
    for(int i=1; i<=2; i++)
    {
        for(int j=1; j<=2; j++)
        {
            if(x.ma[i][j])
            {
                for(int k=1; k<=2; k++)
                {
                    ans.ma[i][k]=(ans.ma[i][k]+(x.ma[i][j]*y.ma[j][k])%m)%m;
                }
            }
        }
    }
    return ans;
}
int main()
{
    long long n;
    while(~scanf("%I64d",&n))
    {
        mod[0]=183120;
        mod[1]=222222224;
        mod[2]=1000000007;
        for(int l=0; l<3; l++)
        {
            if(n==0)
                continue;
            n=n-1;
            matrix a;
            a.ma[1][1]=1;
            a.ma[1][2]=a.ma[2][1]=a.ma[2][2]=0;
            matrix b;
            b.ma[1][1]=3;
            b.ma[1][2]=1;
            b.ma[2][1]=1;
            b.ma[2][2]=0;

            matrix ans;
            for(int i=1; i<=2; i++)
            {
                for(int j=1; j<=2; j++)
                {
                    if(i==j)
                        ans.ma[i][j]=1;
                    else
                        ans.ma[i][j]=0;
                }
            }
            while(n)
            {
                if(n&1)
                    ans=multi(ans,b,mod[l]);
                b=multi(b,b,mod[l]);
                n=n>>1;
            }
            n=ans.ma[1][1];
        }
        printf("%I64d\n",n);
    }
    return 0;
}

时间: 2024-10-12 00:43:42

hdu 4291 A Short problem(矩阵+取模循环节)的相关文章

HDU 4291 A Short problem(矩阵快速幂+循环节)

题目链接": http://acm.hdu.edu.cn/showproblem.php?pid=4291 题意: g(0)=0,g(1)=1; g(n) = 3g(n - 1) + g(n - 2): 求g(g(g(n))) mod 109 + 7 分析: 首先我们得认识到,如果一层一层算是必定会超时的. 其次,取模运算是有循环节的. step1我们找出g(x)%1000000007的循环节 mod1 step2 设g(g(n)) = g(x) x=g(n) 对mod1 取模得到mod2. 剩

HDU 4291 A Short problem(矩阵+循环节)

A Short problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2711    Accepted Submission(s): 951 Problem Description According to a research, VIM users tend to have shorter fingers, compared

HDU 4291 A Short problem 又是一道神奇的矩阵

首先要知道一个姿势,对于Fib数列这类的东西,只要取余就一定会出现循环节.所以上来就直接暴力打表找规律就好了. MOD = 1000000007 发现循环节是 222222224. MOD = 2222222227 发现循环节是 183120 然后这个问题就解决了. 不要问我为啥会出现循环节,我也不会证明... ----------------------------------分割线---------------------------------- 我好像会证明了,试着证一发. 设有一个递推

HDU 4291 A Short problem

A Short problem Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 429164-bit integer IO format: %I64d      Java class name: Main According to a research, VIM users tend to have shorter fingers, compared with Em

HDU 4291 A Short problem 短问题 (递推,微变型)

题意:给出递推式 g(n) = 3g(n - 1) + g(n - 2),且g(1) = 1,g(0) = 0.求g( g( g(n))) mod 109 + 7. 思路:要求的g( g( g(n)))一共里外3层.看到时间限制1s,数据最大10^18,必定不能老实递推,要么有循环,要么用通项公式.这里用通项公式太麻烦了,数字不好算,而g(n)%109 + 7是有规律的, 在n=222222224之后会出现循环,也就是n=0和n=222222224的g(n)是一样的,这是最外层.那么也就是说在g

HDU 5832 A water problem(取模~)—— 2016中国大学生程序设计竞赛 - 网络选拔赛

传送门 A water problem Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 60    Accepted Submission(s): 37 Problem Description Two planets named Haha and Xixi in the universe and they were created wit

HDU 4291 A Short problem (2012成都网络赛,矩阵快速幂+循环节)

链接: click here~~ 题意: According to a research, VIM users tend to have shorter fingers, compared with Emacs users. Hence they prefer problems short, too. Here is a short one: Given n (1 <= n <= 1018), You should solve for g(g(g(n))) mod 109 + 7 where

hdu 3221 Brute-force Algorithm(快速幂取模,矩阵快速幂求fib)

http://acm.hdu.edu.cn/showproblem.php?pid=3221 一晚上搞出来这么一道题..Mark. 给出这么一个程序,问funny函数调用了多少次. 我们定义数组为所求:f[1] = a,f[2] = b, f[3] = f[2]*f[3]......f[n] = f[n-1]*f[n-2].对应的值表示也可为a^1*b^0%p,a^0*b^1%p,a^1*b^1%p,.....a^fib[n-3]*b^fib[n-2]%p.即a,b的指数从n=3以后与fib数列

POJ 1152 An Easy Problem! (取模运算性质)

题目链接:POJ 1152 An Easy Problem! 题意:求一个N进制的数R,保证R能被(N-1)整除时最小的N. 第一反应是暴力.N的大小0到62.发现其中将N进制话成10进制时,数据会溢出.这里有个整除,即(N-1)取模为0. 例子:a1a2a3表示一个N进制的数R,化成10进制: (a1*N*N+a2*N+a3)%(N-1)==((a1*N*N)%(N-1)+(a2*N)%(N-1)+(a3)%(N-1))%(N-1)==(a1+a2+a3)%(N-1): 这样防止了数据的溢出.