hdu5451 矩阵乘法+斐波那契 + 循环节

找循环节:点击打开链接 
正解:点击打开链接
解题思路:
       
          这道题跟斐波拉契数列有关,斐波拉契数列通项公式an= ((1+ √5 )/2)^n+(1- √5 )/2)^n, 这题也可以转化为an=(5+2*sqrt(6))^n+(5-2*sqrt(6))^n 的形式,则an一定是整数的形式,     
         因为an=((5+sqrt(6))+(5-sqrt(6))^n-2*(5+sqrt(6))*(5-sqrt(6)),(5+sqrt(6)+5-sqrt(6))^n=10^n,2*(5+sqrt(6))*(5-sqrt(6))=2,
所以an一定为整数,0<(5-2*sqrt(6)<1,所以0<(5-2*sqrt(6))^n<1,所以这题的y值是an-1。
  就那现在问题就是,怎么来快速的求an?再参考菲波那契数列,通式怎么表达的。a[n]=a[n-1]+a[n-2]。那这里也
可以用类似的表达式,a[n]=p*a[n-1]+q*a[n-2]。带入几个数求得p=10,q=-1,于是通项公式为即a[n]=10*a[n-1]-*a[n-2]。
  由于本题的x比较大,且m比较小,于是可以找循环节,由于是递推关系,后一个只与它前2个有关,于是循环节最大
为m方,另外,循环节肯定从序列开头开始(打表发现的)。

#include <bits/stdc++.h>

using namespace std;

#define MAXN 50000
#define mem(a) memset(a , 0 , sizeof(a))
int a[MAXN];
int judge(int m)
{
    a[0] = 10 % m;
    a[1] = 98 % m;
    for(int i = 2 ; ; i++)
    {
        a[i] = ((a[i-1] * 10 - a[i-2]) % m + m )% m;
        if(a[i] == a[1] && a[i-1] == a[0])
            return i - 1;
    }
}

int Pow(int x , int m)
{
    int cur = 2;
    int res = 1;
    while(x)
    {
        if(x&1)
            res = res * cur % m;
        cur = cur * cur % m;
        x >>= 1;
    }
    return res;
}

int main()
{
    int t , x , m , k = 0;
    scanf("%d" , &t);
    while(t--)
    {
        scanf("%d %d" , &x , &m);
        int tt = judge(m);
        int pos = Pow(x , tt);
        printf("Case #%d: %d\n" , ++k , (a[pos] - 1 + m) % m);
    }
    return 0 ;
}




你可能感兴趣的:(hdu5451 矩阵乘法+斐波那契 + 循环节)