hdu 5451 Best Solver(2015沈阳赛区网赛)

Best Solver

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


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
 


      解题思路:
       
          这道题跟斐波拉契数列有关,斐波拉契数列通项公式an= ((1+ √5 )/2)^n+(1- √5 )/2)^n, 这题也可以转化为an=(5+2*sqrt(6))^n+(5-2*sqrt(6))^n 的形式,则an一定是整数的形式,     
         因为an=((5+sqrt(6))+(5-sqrt(6))^n-2*(5+sqrt(6))*(5-sqrt(6)),(5+sqrt(6)+5-sqrt(6))^n=10^n,2*(5+sqrt(6))*(5-sqrt(6))=2,
所以an一定为整数,0<(5-2*sqrt(6)<1,所以0<(5-2*sqrt(6))^n<1,所以这题的y值是an-1。
  就那现在问题就是,怎么来快速的求an?再参考菲波那契数列,通式怎么表达的。a[n]=a[n-1]+a[n-2]。那这里也
可以用类似的表达式,a[n]=p*a[n-1]+q*a[n-2]。带入几个数求得p=10,q=-1,于是通项公式为a[n]=10*a[n-1]-*a[n-2]。
  由于本题的x比较大,且m比较小,于是可以找循环节,由于是递推关系,后一个只与它前2个有关,于是循环节最大
为m方,另外,循环节肯定从序列开头开始(打表发现的)。


代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=47337;
bool vis[maxn];
int prim[maxn];
int a[maxn];
int judge(int m)
{
    a[0]=10%m;
    a[1]=98%m;
    for(int j=2;; j++)
    {
        a[j]=(a[j-1]*10-a[j-2]+m)%m;
        //int sign=0;
        if(a[j-1]==a[0]&&a[j]==a[1])
        return j-1;
    }
}
int pow_mod(int x,int mod)
{
    long long ans=1,cur=2;
    while(x)
    {
        if(x&1)
            ans=(ans*cur)%mod;
        cur=(cur*cur)%mod;
        x=(x>>1);
    }
    return ans;
}
int main()
{
    int t,ca=1;
    scanf("%d",&t);
    while(t--)
    {
        int m;
        long long x;
        scanf("%I64d%d",&x,&m);
        int cmr=judge(m);
        int cwt=pow_mod(x,cmr);
        printf("Case #%d: ",ca++);
        printf("%d\n",(a[cwt]-1+m)%m);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值