[WC2021] 斐波那契——数论、斐波那契数列

[WC2021] 斐波那契

题解

这里不得不向 Tiw 神下跪~
一道黑题被他讲成一道蓝题难度
根本不会做的我瞬间感觉自己降智了好多

首先发现我们要解决的是满足这个式子:
a f n − 1 + b f n = 0    (   m o d    m ) af_{n-1}+bf_n=0\,\,(\bmod\, m) afn1+bfn=0(modm)的最小的 n n n

我们可以先处理一下,令 c = gcd ⁡ ( a , b , m ) , a ′ = a c , b ′ = b c , m ′ = m c c=\gcd(a,b,m),a'=\frac{a}{c},b'=\frac{b}{c},m'=\frac{m}{c} c=gcd(a,b,m),a=ca,b=cb,m=cm,然后有如下性质:
gcd ⁡ ( gcd ⁡ ( a ′ , m ′ ) , gcd ⁡ ( b ′ , m ′ ) ) = 1 gcd ⁡ ( f n , f n − 1 ) = 1 \gcd(\gcd(a',m'),\gcd(b',m'))=1\\ \gcd(f_n,f_{n-1})=1 gcd(gcd(a,m),gcd(b,m))=1gcd(fn,fn1)=1因为取模 m ′ m' m 不影响与 m ′ m' m gcd ⁡ \gcd gcd,由 gcd ⁡ ( a ′ f n − 1 , m ′ ) = gcd ⁡ ( b ′ f n , m ′ ) \gcd(a'f_{n-1},m')=\gcd(b'f_n,m') gcd(afn1,m)=gcd(bfn,m) 可得:
gcd ⁡ ( a ′ , m ′ gcd ⁡ ( f n − 1 , m ′ ) ) gcd ⁡ ( f n − 1 , m ′ ) = gcd ⁡ ( b ′ , m ′ ) gcd ⁡ ( f n , m ′ gcd ⁡ ( b ′ , m ′ ) ) ⇒ gcd ⁡ ( f n − 1 , m ′ ) gcd ⁡ ( f n , m ′ gcd ⁡ ( b ′ , m ′ ) ) = gcd ⁡ ( b ′ , m ′ ) gcd ⁡ ( a ′ , m ′ gcd ⁡ ( f n − 1 , m ′ ) ) \gcd(a',\frac{m'}{\gcd(f_{n-1},m')})\gcd(f_{n-1},m')=\gcd(b',m')\gcd(f_n,\frac{m'}{\gcd(b',m')})\\ \Rightarrow \frac{\gcd(f_{n-1},m')}{\gcd(f_n,\frac{m'}{\gcd(b',m')})}=\frac{\gcd(b',m')}{\gcd(a',\frac{m'}{\gcd(f_{n-1},m')})}\\ gcd(a,gcd(fn1,m)m)gcd(fn1,m)=gcd(b,m)gcd(fn,gcd(b,m)m)gcd(fn,gcd(b,m)m)gcd(fn1,m)=gcd(a,gcd(fn1,m)m)gcd(b,m)因为两边的分式的分子分母都互质,所以两边都是最简分式,有 gcd ⁡ ( f n , m ′ gcd ⁡ ( b ′ , m ′ ) ) = gcd ⁡ ( a ′ , m ′ gcd ⁡ ( f n − 1 , m ′ ) ) gcd ⁡ ( f n − 1 , m ′ ) = gcd ⁡ ( b ′ , m ′ ) \gcd(f_n,\frac{m'}{\gcd(b',m')})=\gcd(a',\frac{m'}{\gcd(f_{n-1},m')})\\ \gcd(f_{n-1},m')=\gcd(b',m') gcd(fn,gcd(b,m)m)=gcd(a,gcd(fn1,m)m)gcd(fn1,m)=gcd(b,m)而我们需要的只有第二条。

g = gcd ⁡ ( b ′ , m ′ ) g=\gcd(b',m') g=gcd(b,m),那么有 − a ′ b ′ g = f n f n − 1 g    (   m o d    m ′ g ) \frac{-a'}{\frac{b'}{g}}=\frac{f_n}{\frac{f_{n-1}}{g}}\,\,(\bmod\, \frac{m'}{g}) gba=gfn1fn(modgm),此时分母与模数互质,可以求逆元。

于是就得到一种做法:先预处理,枚举所有可能的 m ′ m' m m m m 的因子),然后枚举斐波那契数列,把相邻两项按 g = gcd ⁡ ( f n − 1 , m ′ ) g=\gcd(f_{n-1},m') g=gcd(fn1,m) 分类,每一类用 map 记录到达一种 f n f n − 1 g \frac{f_n}{\frac{f_{n-1}}{g}} gfn1fn 值的最小的 n n n。由于斐波那契在模意义下循环节长度是 O ( 模 数 ) O(模数) O() 的,所以预处理复杂度大概是 m m m 的因子的和带个 log ⁡ \log log,不超过 O ( m log ⁡ 2 m ) O(m\log^2m) O(mlog2m)

询问直接找到对应的 m ′ m' m 对应的类再在 map 里查询即可。

代码

#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define lll __int128
#define uns unsigned
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define END putchar('\n')
#define lowbit(x) ((x)&-(x))
#define inline jzmyyds
using namespace std;
const int MAXN=114514;
const ll INF=1e18;
ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
	return f?x:-x;
}
int ptf[50],lpt;
void print(ll x,char c='\n'){
	if(x<0)putchar('-'),x=-x;
	ptf[lpt=1]=x%10;
	while(x>9)x/=10,ptf[++lpt]=x%10;
	while(lpt>0)putchar(ptf[lpt--]^48);
	if(c>0)putchar(c);
}
int Q,m;
unordered_map<int,unordered_map<int,int> >mp[MAXN];
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
ll exgcd(ll a,ll b,ll&x,ll&y){
	if(!b)return x=1,y=0,a;
	ll d=exgcd(b,a%b,y,x);
	return y-=a/b*x,d;
}
ll inv(ll a,ll p){
	ll x,y,d=exgcd(a,p,x,y);
	if(d!=1)return 1145141919810;
	return (x%p+p)%p;
}
int main()
{
	Q=read(),m=read(),mp[1][1][0]=2;
	for(int x=2;x<=m;x++)if(m%x==0){
		ll a=1,b=1;
		for(int i=2;;i++,swap(a,b),(b+=a)%=x){
			ll d=gcd(a,x),c=b*inv(a/d,x/d)%(x/d);
			if(mp[x][d].count(c))break;
			mp[x][d][c]=i;
		}
	}
	while(Q--){
		ll a=read(),b=read();
		if(!a){print(0);continue;}
		if(!b){print(1);continue;}
		ll d=gcd(gcd(a,b),m),k=m/d;
		a/=d,b/=d,d=gcd(b,k);
		ll c=(m-a)*inv(b/d,k/d)%(k/d);
		auto it=mp[k][d].find(c);
		if(it!=mp[k][d].end())print(IS);
		else print(-1);
	}
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值