有点复杂的数列

题目描述
acndy喜欢做数学题,学了数论以后更是一发不可收拾,他发现一个数列:

这里写图片描述

给出n,a,b,c的值,他想算出fn模p后的值。

输入
第一行一个数T,为测试数据组数,
每组数据一行,一行五个正整数,按顺序为n,a,b,c,p,
1<=T<=10,1<=n<=1e18,1<=a,b,c<=1e9,p是质数且p<=1e9+7。
输出
对每组数据输出一行一个数,输出fn对p取模后的数值
提示
费马小定理: 假如p是质数,且gcd(a,p)=1,那么 a^(p-1)%p=1。

发现好久没有写博客了。
评价:额,算难题么?只要知道矩阵快速幂就会做了。偏简单题,但是要注意细节

易知

f(n)=ag(n) f ( n ) = a g ( n )
g(n)=cg(n1)+g(n2)+b g ( n ) = c g ( n − 1 ) + g ( n − 2 ) + b

g(1)=0,g(2)=b g ( 1 ) = 0 , g ( 2 ) = b

显然是构成3乘3的矩阵。
g(n)g(n1)b=c10100101g(n1)g(n2)b [ g ( n ) g ( n − 1 ) b ] = [ c 1 1 1 0 0 0 0 1 ] ∗ [ g ( n − 1 ) g ( n − 2 ) b ]

所以:
g(n)g(n1)b=c10100101n2b0b(n>2) [ g ( n ) g ( n − 1 ) b ] = [ c 1 1 1 0 0 0 0 1 ] n − 2 ∗ [ b 0 b ] ( n > 2 )

这样的话,就只要当作快速幂来做就好了,只不过重新定义一下乘法而已。

代码:

import java.util.Scanner;




public class Main
{
    static long n,a,b,c,p;
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        //System.out.println(P(3,186));
        int t=sc.nextInt();
        while((t--)>0)
        {
            n=sc.nextLong();
            a=sc.nextLong();
            b=sc.nextLong();
            c=sc.nextLong();
            p=sc.nextLong();
            a%=p;
            if(a==1||n==1)
                System.out.println(1);
            else
                if(a%p==0)
                {
                    if(n==1)
                        System.out.println(1);
                    else
                        System.out.println(0);
                }//按照得分,上面那些情况,数据是没有的,不写也无所谓了
                else
                {
                    if(n==2)
                        System.out.println(P(a,b));
                    else
                    {
                        M ans=M.unit();//单位矩阵
                        M A=new M();
                        A.a[0][0]=c;
                        A.a[0][1]=1;
                        A.a[0][2]=1;
                        A.a[1][0]=1;
                        A.a[2][2]=1;//设置系数

                        n-=2;
                        while(n>0)
                        {
                            if((n&1)==1)
                                ans=ans.mui(A, p-1);                        
                            A=A.mui(A,p-1);//这里要注意了,是对p-1取模,我就死在这了,想当然对p取模了
                            n>>=1;
                        }//纯粹模拟快速幂
                        long top=(b*ans.a[0][0]+b*ans.a[0][2])%(p-1);
                        //System.out.println(top);
                        System.out.println(P(a,top));
                    }
                }
        }
    }
    static long P(long x,long k)
    {
        long ans=1;
        while(k>0)
        {
            if((k&1)==1)
                ans=ans*x%p;
            x=x*x%p;
            k>>=1;
        }
        return ans;
    }
}

class M
{
    long a[][]=new long[3][3];
    static M unit()
    {
        M m=new M();
        m.a[0][0]=1;
        m.a[1][1]=1;
        m.a[2][2]=1;
        return m;
    }
    M mui(M o,long mod)//定义乘法
    {
        M ans=new M();
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            {
                ans.a[i][j]=0;
                for(int k=0;k<3;k++)
                    ans.a[i][j]=(ans.a[i][j]+a[i][k]*o.a[k][j]%mod)%mod;
            }
        return ans;
    }
}

你可能感兴趣的:(蓝桥杯,矩阵快速幂)