HDU 3221Brute-force Algorithm(降冪公式 神似hdu4549)

果7發表於2013-10-17

Brute-force Algorithm

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1940    Accepted Submission(s): 475


Problem Description
Professor Brute is not good at algorithm design. Once he was asked to solve a path finding problem. He worked on it for several days and finally came up with the following algorithm:

Any fool but Brute knows that the function “funny” will be called too many times. Brute wants to investigate the number of times the function will be called, but he is too lazy to do it.

Now your task is to calculate how many times the function “funny” will be called, for the given a, b and n. Because the answer may be too large, you should output the answer module by P.
 

Input
There are multiple test cases. The first line of the input contains an integer T, meaning the number of the test cases.

For each test cases, there are four integers a, b, P and n in a single line.
You can assume that 1≤n≤1000000000, 1≤P≤1000000, 0≤a, b<1000000.
 

Output
For each test case, output the answer with case number in a single line.
 

Sample Input
3 3 4 10 3 4 5 13 5 3 2 19 100
 

Sample Output
Case #1: 2 Case #2: 11 Case #3: 12
 

Source
 


題目大意:這個題目主要開始感覺意思難懂一點,實際上就是迭代的思想,f(1)=a,  f(2)=b,  f(3)=f(2,f(1))=f(1)*f(2)=a*b,  f(4)=f(3,f(2))=f(3)*f(2)=a*b^2,  f(5)=a^2*b^3.....後面的規律就一目瞭然了吧,然後給你一個地址。hdu4549M斐波那契數列題目真的是驚人的相似.

      解題思路:只是兩者有一點不同,前面那個hdu4549直接%1e9+7,
小費馬定理a^(p-1)%p==1,(a,p互質,且p為質數),很顯然p==1e9+7滿足這個條件,所以可以用小費馬定理降冪:a^t%p==a^(t%(p-1))。可以理解為p-1為一個迴圈節。 但是這個題目就不是這樣了,這也是兩點的不同之處!這個p可能不是質數,因此費馬小定理失效,但是可以用降冪公式:(A^x)%C=A^(x%phi(C)+phi(C))%C(x>=phi(C)).主要思想就是用矩陣的快速冪把a,b的指數算出來,注意算指數的時候結合降冪公式,然後最後直接用快速冪算出結果即可。

      題目地址:Brute-force Algorithm

如果對矩陣的快速冪那一塊或者開始推出fibo數列這塊不清楚的,可以看HDU 4549M斐波那契數列(矩陣快速冪+費馬小定理)


AC程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
using namespace std;
__int64 mo,phi;
__int64 ret[2][2],tmp[2][2],p[2][2];
__int64 n;

void init()  //初始化
{
    ret[0][0]=1; ret[0][1]=1;
    ret[1][0]=1; ret[1][1]=0;
    p[0][0]=1; p[0][1]=1;
    p[1][0]=1; p[1][1]=0;
}

void cal1()  //!(n&1)
{
    int i,j,k;
    for(i=0;i<2;i++)
        for(j=0;j<2;j++)
        {
            tmp[i][j]=p[i][j];
            p[i][j]=0;
        }

    for(i=0;i<2;i++)
        for(j=0;j<2;j++)
          for(k=0;k<2;k++)
          {
                p[i][j]=p[i][j]+tmp[i][k]*tmp[k][j];
                if(p[i][j]>=phi)
                    p[i][j]=p[i][j]%phi+phi;
          }
}

void cal2()  //n&1
{
    int i,j,k;
    for(i=0;i<2;i++)
        for(j=0;j<2;j++)
        {
            tmp[i][j]=ret[i][j];
            ret[i][j]=0;
        }

    for(i=0;i<2;i++)
        for(j=0;j<2;j++)
          for(k=0;k<2;k++)
          {
              ret[i][j]=ret[i][j]+tmp[i][k]*p[k][j];
              if(ret[i][j]>=phi)
                ret[i][j]=ret[i][j]%phi+phi;
          }
}

void fastmi()  //矩陣的快速冪
{
    init();
    n-=3;
    while(n)
    {
        if(n&1)
            cal2();
        cal1();
        n>>=1;
    }
}

__int64 pow(__int64 base,__int64 p)  //快速冪
{
    __int64 ans=1;
    while(p)
    {
        if(p&1)
            ans=(ans*base)%mo;
        base=(base*base)%mo;
        p>>=1;
    }
    return ans;
}

__int64 geteuler(__int64 n)
{
    __int64 m=sqrt(n+0.5),ans=n,i;
    for(i=2;i<=m;i++)
        if(n%i==0)
        {
            ans=ans/i*(i-1);
            while(n%i==0)
                n/=i;
        }
    if(n>1)
        ans=ans/n*(n-1);
    return ans;
}

int main()
{
    __int64 a,b;
    int i,tes;
    scanf("%d",&tes);
    for(i=1;i<=tes;i++)
    {
        scanf("%I64d%I64d%I64d%I64d",&a,&b,&mo,&n);
        n--;
        phi=geteuler(mo);   //得到尤拉值
        __int64 ans1,ans2,res1,res2;
        if(n==0) ans1=1,ans2=0;
        else if(n==1) ans1=0,ans2=1;
        else if(n==2) ans1=1,ans2=1;
        else
        {
            fastmi();
            ans2=(ret[0][0]+ret[0][1]);  //b的次數
            ans1=(ret[1][0]+ret[1][1]);  //a的次數
        }

        //printf("%I64d %I64d\n",ans1,ans2);
        if(ans1>=phi)
            ans1=ans1%phi+phi;
        if(ans2>=phi)
            ans2=ans2%phi+phi;
        res1=pow(a,ans1);
        res2=pow(b,ans2);
        __int64 res=(res1*res2)%mo;
        printf("Case #%d: %I64d\n",i,res);
    }
    return 0;
}

//0MS



相關文章