hdu 5451 Best Solver 快速矩阵乘法 Fibonacci数列的循环节

Best Solver

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 401    Accepted Submission(s): 212


Problem Description
The so-called best problem solver can easily solve this problem, with his/her childhood sweetheart.

It is known that y=(5+26)1+2x .
For a given integer x (0x<232) and a given prime number M (M46337) , print [y]%M . ( [y] means the integer part of y )
 

Input
An integer T (1<T1000) , indicating there are T test cases.
Following are T lines, each containing two integers x and M , as introduced above.
 

Output
The output contains exactly T lines.
Each line contains an integer representing [y]%M .
 

Sample Input
   
   
   
   
7 0 46337 1 46337 3 46337 1 46337 21 46337 321 46337 4321 46337
 

Sample Output
   
   
   
   
Case #1: 97 Case #2: 969 Case #3: 16537 Case #4: 969 Case #5: 40453 Case #6: 10211 Case #7: 17947
 

Source
2015 ACM/ICPC Asia Regional Shenyang Online

本题正解是:快速矩阵乘法+ Fibonacci数列的循环节

以下是队里某同学的方法:

首先(5+2sqrt(6))^n + (5-2sqrt(6))^n 是一个整数,且(5-2sqrt(6))^n < 1

所以 (5+2sqrt(6))^n + (5-2sqrt(6))^n = x + y sqrt(6) + x - ysqrt(6)

所以算出 (5+2sqrt(6))^n的整数部分x,答案就是2*x-1

中间过程可以用取模操作。

他的思路是:1+2^x ,把1提出来,最后乘上即可。

对于{(5+2sqrt(6))^(2^n)}^2 = (5+2sqrt(6))^(2^(n+1))

这个乘法是有循环结的。

可能循环节开始位置不是(5+2sqrt(6))所以,预处理即可。

找到循环节以后,取模,然后快速矩阵乘即可。看代码。


#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstdio>
using namespace std;
#define ll unsigned int
struct Node{
    int a,b,t;
    Node(){}
    Node(int _a,int _t){
        a = _a;
        t = _t;
    }
};
vector<Node> head[50000];
ll mod ;
struct Mat{
    ll a[2][2];
    Mat(){
        memset(a,0,sizeof(a));
    }
    Mat operator *(const Mat & b){
        Mat c;
        memset(c.a,0,sizeof(c.a));
        for(int i = 0;i < 2; i++)
            for(int j = 0;j < 2; j++)
                for(int k = 0;k < 2; k++)
                    c.a[i][j] = (c.a[i][j]+a[i][k]*b.a[k][j])%mod;
        return c;
    }
};

int main(){
    ll t,n,m,tt=1;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        mod = m;
        for(int i = 0;i < m; i++)
            head[i].clear();
        Node a,b;
        Mat x,y;
        ll cnt = 1,be=0;
        x.a[0][0] = x.a[1][1] = 5%mod;
        x.a[0][1] = 12%mod;
        x.a[1][0] = 2%mod;
        y = x;
        for(;;cnt++){
            a.a = x.a[1][0];
            a.b = x.a[0][0];
            a.t = cnt;
            int flag = 1;
            for(int i = 0;i < head[a.b].size(); i++){
                if(head[a.b][i].a == a.a){
                    flag = 0;
                    be = head[a.b][i].t;
                 }
            }
            if(flag==0) break;
            head[a.b].push_back(a);
            x = x*x;
        }
        cnt = cnt - be;
        ll num = 0,ans;
        x = y;

        for(int i = 0;i < min(be,n); i++){
            x = x*x;
        }
        if(n > be){
            n -= be;
            cnt = n%cnt;
            for(int i = 0;i < cnt; i++)
                x = x*x;
        }
        x = y * x;
        ans = 2*x.a[0][0]-1;
        ans %= mod;
        printf("Case #%lld: %lld\n",tt++,ans);
    }
    return 0;
}


出题人的解法:(过后更新)







你可能感兴趣的:(HDU,best,Solver,5451,Fibonacci数列的循环节,快速矩阵乘法)