hdu5667Sequence(矩阵快速幂+数学化解)

这道以我也是服了,折腾了一天。对我这样的新手菜鸡而言,这道题拿到就先试了一下暴力(初生牛犊不怕虎T_T),T了之后就没想到办法了,然后看了一下搜了一下思路,矩阵快速幂!!!我居然把这档子事儿给忘了,递推式,数据爆炸,太符合应用场景了,于是就开始着手往这方走,但是怎么也化不出相加 形式,上网弄了好久才明白,我还是觉得很多博客太跳了,一开始的式子我就不知道哪儿来的。不过最后还是找到了一位大佬的,然后弄懂了,这里分享一下我看懂的。
在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<vector>
#include<time.h>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<functional>
#include<map>
#include<queue>
#define mod (1000000000+7)
#define maxn 10000000+5
#define SIZE 200000+10
typedef long long ll;
const int inf_max = 0x3f3f3f3f;
const int inf_min = 0xc0c0c0c0;
using namespace std;
ll n,a,b,c,p,l,ny_c;   //l表示从左到i个位置出现了几个左括号,r表示从右边到位置i有几个右括号
struct Mat
{
    ll mat[3][3];
}e,start,t;

ll Fast_power(ll base,ll power,ll m)    //正确
{
    base%=m;
    ll res=1;
    while(power)
    {
        if(power&1)
            res=res*base%m;
        base=base*base%m;
        power>>=1;
    }
    return res%m;
}

Mat Multi(Mat a, Mat b,ll m)
{
    Mat c;
    memset(c.mat, 0, sizeof(c.mat));
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
                c.mat[i][j] = (c.mat[i][j] +a.mat[i][k] * b.mat[k][j])%(m-1);
    return c;
}
Mat Mat_fpower(Mat base,ll power,ll m)      //正确
{
    Mat res=e;
    while(power)
    {
        if(power&1)
            res=Multi(res,base,m);
        base=Multi(base,base,m);
        power>>=1;
    }
    return res;
}

void Initial(ll a,ll b,ll c,ll m)
{
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        {
            if(i==j)
                e.mat[i][j]=1;
        }
    start.mat[0][1]=1;start.mat[0][0]=c%m;start.mat[1][0]=1;
    start.mat[2][2]=1;start.mat[2][0]=1;
    t.mat[0][0]=b%m,t.mat[0][2]=b%m;
}
void Input()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            {
                t.mat[i][j]=0;
                start.mat[i][j]=0;
                e.mat[i][j]=0;
            }
        scanf("%I64d%I64d%I64d%I64d%I64d",&n,&a,&b,&c,&p);
        if(n==1)
        {
            printf("1\n");
        }
        else if(n==2)
        {
            printf("%I64d\n",Fast_power(a,b,p));
        }
        else
        {
            Initial(a,b,c,p);
            Mat tmp=Mat_fpower(start,n-2,p);
            Mat ans=Multi(t,tmp,p);
            ll t1=ans.mat[0][0];
            if(a%p)
            {
                t1%=(p-1);
                printf("%I64d\n",Fast_power(a,t1,p));
            }
            else
            {
                if(t1<(p-1))
                    printf("%I64d\n",Fast_power(a,t1,p));
                else
                {
                    t1=t1%(p-1)+p-1;
                    printf("%I64d\n",Fast_power(a,t1,p));
                }
            }
        }

    }
}
int main()
{
    Input();
    return 0;
}

总结一下出现的问题吧,首先就是矩阵快速幂的时候%(p-1),一开始根本没注意到这个问题,以为只有最后把kn求出来后才需要模(p-1),结果在矩阵乘法的时候就要%(p-1)了;再者就是对于对于运算结果的取余问题,该取余的地方一定要取,否则连错在哪儿都难找(前天ans忘了取余debug了一上午T_T).数论对我有点儿不太友好,能过得基本一趟,不能过的至少debug半天,果然还是我太菜了吧.

发布了33 篇原创文章 · 获赞 14 · 访问量 446

猜你喜欢

转载自blog.csdn.net/qq_44077455/article/details/96694489