题面是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;
}