hdoj 5451 Best Solver 【求循环节 + 矩阵快速幂】



Best Solver

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


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
 



比赛时卡在这道题了,醉了。


打表找出循环节loop = (M - 1) * (M + 1),然后求解 2^n % loop,下面就是矩阵快速幂裸题了。


提交6次代码才过,CE5次。杭电要炸了。。。


找循环节解析链接:点我

裸题链接:点我



AC代码:


#include <cstdio>
#include <cstring>
#include <cmath>
#define LL long long
struct Matrix
{
    LL a[3][3];
};
Matrix ori, res;
LL M;
void init()
{
    memset(ori.a, 0, sizeof(ori.a));
    memset(res.a, 0, sizeof(res.a));
    for(int i = 0; i < 2; i++)
        res.a[i][i] = 1;
    ori.a[0][0] = 5, ori.a[0][1] = 2;
    ori.a[1][0] = 12, ori.a[1][1] = 5;
}
Matrix muitl(Matrix x, Matrix y)
{
    Matrix z;
    memset(z.a, 0, sizeof(z.a));
    for(int i = 0; i < 2; i++)
    {
        for(int k = 0; k < 2; k++)
        {
            if(x.a[i][k] == 0) continue;
            for(int j = 0; j < 2; j++)
                z.a[i][j] = (z.a[i][j] + (x.a[i][k] * y.a[k][j]) % M) % M;
        }
    }
    return z;
}
LL F[3], ans[3];
int k = 1;
void solve(LL n)
{
    while(n)
    {
        if(n & 1)
            res = muitl(ori, res);
        ori = muitl(ori, ori);
        n >>= 1;
    }
    for(int i = 0; i < 2; i++)
    {
        ans[i] = 0;
        for(int k = 0; k < 2; k++)
            ans[i] = (ans[i] + (F[k] * res.a[k][i]) % M) % M;
    }
    printf("Case #%d: %lld\n", k++, (2*ans[0] - 1) % M);
}
LL pow_mod(LL a, LL p, LL n)
{
    if(p == 0) return 1;
    LL ans = pow_mod(a, p/2, n);
    ans = ans * ans % n;
    if(p % 2 == 1) ans = ans * a % n;
    return ans;
}
int main()
{
    int t;
    LL n, N;
    F[0] = 5, F[1] = 2;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%lld%lld", &n, &M);
        LL loop = (M+1) * (M-1);//循环节
        LL N = pow_mod(2, n, loop) + 1;//快速幂 求解2^n % loop
        init();//构造矩阵
        solve(N-1);//矩阵快速幂
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值