UVA 11582 Colossal Fibonacci Numbers! 规律题 练习unordered_set

        题面是PDF的,这里大概说一下题意好了,给出三个数a,b,n。询问斐波那契数列的第a^b项%n是多少,这里的^表示幂,而不是异或

        大概是这样的做法

        考虑找出循环节,然后计算a^b是位于循环节的什么位置

        定义一个函数,F(i)=f(i)%n,其中f(i)表示斐波那契数列的第i项,然后考虑二元组(F(i),F(i+1)),由于斐波那契数列的递推公式仅仅和前两项有关,我们可以知道,当该二元组重复时,整个序列就开始重复了

        然后最大的周期可能是多少呢?由于二元组的每一项都是%n的,每一项都有n种可能,因此这个二元组一共最多有n^2种可能。

        暴力跑出周期,然后对a^b弄一个%周期的快速幂就好

        用了unordered_set来判重,由于是pair,就自己写了一个hash函数,因为n最大只有1000,所以我那样hash是绝对不会冲突的

        这样的写法能理解就理解吧,基本上就是向命名空间std中添加了一个hash<pa>的模板具体化的结构体,然后unordered_set会自动调用这个hash函数来hash我的pa

        除此之外,unordered_set的insert函数在只接受一个valueType的时候是返回的一个pair(此外还有接受一个iterator和一个valueType的重载的insert,这个只返回一个iterator。还有insert重载就不赘述了),这个pair的first是指向新插入元素的iterator,second是一个bool,表明了是否成功的插入,因此利用first中的iterator可以解除引用后再次写到vector的push_back里面去。。

        此外跑了一个快速幂,m是代表我的周期

        基本上就是当做给使用unordered_set练练手吧

#include <iostream>
#include <unordered_set>
#include <algorithm>
#include <vector>

using namespace std;
typedef unsigned long long ull;
typedef pair<ull,ull> pa;
namespace std{
    template<>
    struct hash<pa>{
        typedef pa argument_type;
        typedef std::size_t result_type;
        result_type operator()(const pa& p)const{return p.first*1001+p.second;}
    };
}
typedef unordered_set<pa> uset;

ull times,n,a,b,m,qpow();
uset s;
vector<pa> v;
void getm();

int main(){
    ios_base::sync_with_stdio(0);
    cin>>times;
    while(times--){
        cin>>a>>b>>n;
        getm();
        cout<<v[qpow()-1].first<<endl;
        s.clear();v.clear();
    }
    return 0;
}

void getm(){
    if(n==1){
        v.push_back(make_pair(0ull,0ull));
        return;
    }
    m=2;
    pa tmp[2]{make_pair(1ull%n,2ull%n),make_pair(1ull%n,1ull%n)};
    v.push_back(*(s.insert(tmp[1]).first));
    v.push_back(*(s.insert(tmp[0]).first));
    for(ull i=1;;i^=1){
        tmp[i&1].first=tmp[1^(i&1)].second%n;
        tmp[i&1].second=(tmp[1^(i&1)].first+tmp[1^(i&1)].second)%n;
        if(s.find(tmp[i&1])==s.end())
            ++m,v.push_back(*(s.insert(tmp[i&1]).first));
        else
            return;
    }
}

ull qpow(){
    if(n==1)
        return 1;
    ull res=1,time=b,tmp=a%m;
    while(time){
        if(time&1)
            res*=tmp,res%=m;
        tmp*=tmp,tmp%=m;
        time>>=1;
    }
    return res;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值