Colossal Fibonacci Numbers! 巨大的斐波那契数 UVA - 11582

给你a b n,然后让你计算f(a^b)%n的值
这个题做了蛮久。首先是对这么大的数不知所措。计算f(a^b)%n,首先a^b,就已经很大了好吧,其中0<=a,b<2e64,都超过long long 的范围了。

然后参考了下dalao 们的博客,这个主要是发现斐波那契数列模上一个数之后,是会出现循环的。因为f[i]是由f[i-1],f[i-2]推出来的,如果f[i-1]和f[i-2]出现过了,即出现了循环。因为 模上n,一共有n种余数,然后f[i-1],f[i-2]连续两个数出现相同的话,一共不超过n^2;

a,b用什么存呢?法一:用unsighed long long ,范围刚好合适。法二用大数

如果不加if(a==0||n==1) printf(“0\n”);会RE,因为当n=1的时候,f[i]都是0.根本找不到两个1。
开始的想法是,我先预处理一个斐波那契的表,先模上1000,因为最大n的是1000,然后对于具体的值,我就直接模上具体的值。但是这样是有问题的。因为如果给你的数是1005,这个模1000是5,然后模3是二。但是1005直接模3 是0.。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>

using namespace std;
const int maxn = 1e6+10;
int f[maxn];
#define inf 10000
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        unsigned long long a,b;
        int n;
        scanf("%llu %llu %d",&a,&b,&n);
        int flag=0,time;
        if(a==0||n==1) {printf("0\n");continue;}
        f[0]=0;f[1]=f[2]=1;
        for(int i=3;i<maxn;i++)
        {
            f[i]=(f[i-1]+f[i-2])%n;
           if(f[i]%n==1&&f[i-1]%n==1) {time=i-2;break;}
        }
        unsigned long long temp=b,q=a%time,ans=1;
        while(temp)
        {
            if(temp&1) ans=(ans*q%time)%time;
            q=(q*q)%time;
            temp=temp/2;
        }
       if(ans==0) ans=time;
        printf("%d\n",f[ans]%n);
    }
    return 0;
}

大数

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>

using namespace std;
const int maxn = 1e6+10;
int f[maxn];
char a[100],b[100];
#define inf 10000
long long mo(char c[],int time)
{
    int len=strlen(c);
    long long ans=0;
    for(int i=0;i<len;i++)
    {
        ans=((ans*10)+c[i]-'0')%time;
    }
    return ans;
}
long long chu(char c[],int shu)
{
    int len=strlen(c);
    long long ans=0,ys=0;
    for(int i=0;i<len;i++)
    {
        ans=ans*10+(ys*10+c[i]-'0')/shu;
        ys=(ys*10+c[i]-'0')%shu;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%s %s %d",a,b,&n);
        int flag=0,time;
        if(a[0]=='0'||n==1) {
            printf("0\n");
            continue;
        }
        f[0]=0;f[1]=f[2]=1;
        for(int i=3;i<maxn;i++)
        {
           f[i]=(f[i-1]+f[i-2])%n;
           if(f[i]==f[i-1]&&f[i]==1)
           {
               time=i-2;
               break;
           }
        }
        long long ans=0;
        long long q=mo(a,time);
        int blen=strlen(b);
        if((b[blen-1]-'0')%2==0) ans=1;
        else ans=q;
        q=(q*q)%time;
        long long temp=chu(b,2);
        while(temp)
        {
            if(temp&1) ans=(ans*q%time)%time;
            q=(q*q)%time;
            temp=temp/2;
        }
        if(ans==0) ans=time;
        printf("%d\n",f[ans]%n);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值