• HDOJ 5667 Sequence//费马小定理 矩阵快速幂


    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5667

    题意:如题给了一个函数式,给你a,b,c,n,p的值,叫你求f(n)%p的值

    思路:先对函数取以a为底的log,令g(n)=log(a)(f(n)),结果就能得到

    g(n)=b+c*g(n-1)+g(n-2);(n>3)

    g(n)=0;(n=1)

    g(n)=b;(n=2)

              g(n)    c  1  1    g(n-1)

    用矩阵表示出来就是 g(n-1) = 1  0  0    *  g(n-2)

                 b    0  0 1    b

    设中间的矩阵为A 那么要求g(n)就是用A^(n-2)*g(2)来求得

                          g(1)  

                            b

    而我们要求的是 f(n)%p,f(n)=a^g(n),很明显g(n)是会爆的,那么因为p是质数,所以f(n)%p=(a^(g(n)%(p-1))%p

    用快速幂一样的思路来模拟矩阵的乘法就行了

    矩阵的乘法三个for循环就能写掉

    for(int i=1;i<=n;i++)

      for(int j=1;j<=n;j++)

        for(int k=1;k<=n;k++)

          tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]);

    然后设置三个矩阵,一个初始化为单位矩阵用来存储答案,一个存储当前的值,一个用来计算。

    之后求出了g(n)的值之后,对原式还是要做一次快速幂,注意特判a%p==0的情况,0^0=1不处理

     1 #include <stdio.h>
     2 #include <iostream>
     3 #include <string.h>
     4 #include <stdlib.h>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <math.h>
     8 using namespace std;
     9 long long  x[10][10];
    10 long long  y[10][10];
    11 long long  t;
    12 long long  n,a,b,c,p;
    13 long long qpow1(long long a1,long long n1 )
    14 {
    15     long long ans=1;
    16     while(n1)
    17     {
    18         if(n1&1)
    19             ans=ans*a1%p;
    20         a1=a1*a1%p;
    21         n1>>=1;
    22     }
    23     return ans;
    24 }
    25 void qpow(long long n1)
    26 {
    27     long long  tmp[10][10];
    28     memset(x,0,sizeof(x));
    29     for(int i=0;i<3;i++)
    30         x[i][i]=1;
    31     
    32     while(n1)
    33     {
    34         memset(tmp,0,sizeof(tmp));
    35         if(n1&1)
    36         {
    37             for(int i=0;i<3;i++)
    38             {
    39                 for(int j=0;j<3;j++)
    40                 {
    41                     for(int k=0;k<3;k++)
    42                     {
    43                         tmp[i][j]=(tmp[i][j]+x[i][k]*y[k][j]) % (p-1);
    44                     }
    45                 }
    46             }
    47             for(int i=0;i<3;i++)
    48                 for(int j=0;j<3;j++)
    49                     x[i][j]=tmp[i][j];
    50         }
    51         memset(tmp,0,sizeof(tmp));
    52         for(int i=0;i<3;i++)
    53         {
    54             for(int j=0;j<3;j++)
    55             {
    56                 for(int k=0;k<3;k++)
    57                 {
    58                     tmp[i][j]=(tmp[i][j]+y[i][k]*y[k][j]) % (p-1);
    59                 }
    60             }
    61         }
    62         for(int i=0;i<3;i++)
    63             for(int j=0;j<3;j++)
    64                 y[i][j]=tmp[i][j];
    65         n1>>=1;
    66     }
    67 }
    68 int main()
    69 {
    70     scanf("%lld",&t);
    71     while(t--)
    72     {
    73         scanf("%lld %lld %lld %lld %lld",&n,&a,&b,&c,&p);
    74         if(a%p==0)
    75         {
    76             printf("0
    ");
    77             continue;
    78         }
    79         memset(y,0,sizeof(y));
    80         y[0][0]=c,y[0][1]=1,y[0][2]=1;
    81         y[1][0]=1,y[1][1]=0,y[1][2]=0;
    82         y[2][0]=0,y[2][1]=0,y[2][2]=1;
    83         qpow(n-2);
    84         long long ans1=(x[0][0]*b+b*x[0][2])%(p-1);
    85         printf("%lld
    ",qpow1(a,ans1));
    86     }
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    POJ 3292 Semi-prime H-numbers (素数筛法变形)
    POJ 1845 Sumdiv (整数拆分+等比快速求和)
    POJ 2635 The Embarrassed Cryptographer(大数求余)
    POJ 2115 C Looooops (扩展欧几里德 + 线性同余方程)
    poj3071
    poj2486
    poj1947
    POJ 1159
    POJ 1845
    poj3282
  • 原文地址:https://www.cnblogs.com/as3asddd/p/5430594.html
Copyright © 2020-2023  润新知