【2022省选模拟】GCD——数论、矩阵加速

找不到原题链接

题目描述

在这里插入图片描述
在这里插入图片描述

题解

又要求 gcd ⁡ \gcd gcd,又要取模,就只能用好 gcd ⁡ \gcd gcd 的性质了。这道题的核心思想是利用 gcd ⁡ ( a , b ) = gcd ⁡ ( a   m o d   b , b ) = gcd ⁡ ( a , b   m o d   a ) \gcd(a,b)=\gcd(a\bmod b,b)=\gcd(a,b\bmod a) gcd(a,b)=gcd(amodb,b)=gcd(a,bmoda),那么我们在求两个大数的 gcd ⁡ \gcd gcd 时,可以试着把其中一个数变小以直接计算。

首先如果向量 ( a , b ) (a,b) (a,b) ( c , d ) (c,d) (c,d) 线性相关,那么最大公因数就是两边中较小的那个,否则我们可以用辗转相除消元的方法消掉 d d d,把问题转化为求 A n s = gcd ⁡ ( a f n + b f n + 1 , c f n ) Ans=\gcd(af_n+bf_{n+1},cf_n) Ans=gcd(afn+bfn+1,cfn)

考虑先求 G = gcd ⁡ ( a f n + b f n + 1 , f n ) G=\gcd(af_n+bf_{n+1},f_n) G=gcd(afn+bfn+1,fn),然后再求 A n s = G ⋅ gcd ⁡ ( a f n + b f n + 1 G , c ) Ans=G\cdot \gcd(\frac{af_n+bf_{n+1}}{G},c) Ans=Ggcd(Gafn+bfn+1,c)。设 g n = gcd ⁡ ( f n , f n + 1 ) g_n=\gcd(f_n,f_{n+1}) gn=gcd(fn,fn+1),那么有
G = gcd ⁡ ( a f n + b f n + 1 , f n ) = gcd ⁡ ( b f n + 1 , f n ) = g n ⋅ gcd ⁡ ( b , f n g n ) G=\gcd(af_n+bf_{n+1},f_n)=\gcd(bf_{n+1},f_n)=g_n\cdot \gcd(b,\frac{f_n}{g_n}) G=gcd(afn+bfn+1,fn)=gcd(bfn+1,fn)=gngcd(b,gnfn)通过打表发现 g n = 3 ⌊ n 2 ⌋ g_n=3^{\lfloor\frac{n}{2}\rfloor} gn=32n,所以我们可以用矩阵加速来求 f n g n \frac{f_n}{g_n} gnfn。这个除法只需要稍稍修改一下每两步的转移矩阵即可,因为转移矩阵平方的每个数都是3的倍数。

我们求得 f n g n \frac{f_n}{g_n} gnfn 在取模 b b b 意义下的值过后,就可以直接算 gcd ⁡ ( b , f n g n ) \gcd(b,\frac{f_n}{g_n}) gcd(b,gnfn)

设我们求得的 gcd ⁡ ( b , f n g n ) = k \gcd(b,\frac{f_n}{g_n})=k gcd(b,gnfn)=k,现在来考虑答案的式子怎么算:
A n s = G ⋅ gcd ⁡ ( a f n + b f n + 1 G , c ) = g n k ⋅ gcd ⁡ ( a f n g n + b f n + 1 g n k , c ) Ans=G\cdot \gcd(\frac{af_n+bf_{n+1}}{G},c)\\ =g_nk\cdot \gcd(\frac{a\frac{f_n}{g_n}+b\frac{f_{n+1}}{g_n}}{k},c) Ans=Ggcd(Gafn+bfn+1,c)=gnkgcd(kagnfn+bgnfn+1,c)
我们需要求出 a f n g n + b f n + 1 g n k \frac{a\frac{f_n}{g_n}+b\frac{f_{n+1}}{g_n}}{k} kagnfn+bgnfn+1 在取模 c c c 意义下的值以方便直接计算。注意到 f n g n , b \frac{f_n}{g_n},b gnfn,b 都保证是 k k k 的倍数,而 ∀ b ∣ a , a b   m o d   c = a   m o d   b c b \forall b|a,\frac{a}{b}\bmod c=\frac{a\bmod bc}{b} ba,bamodc=bamodbc,所以我们用矩阵求出上面部分   m o d   k c \bmod kc modkc 的值,然后直接除以 k k k 即可。

复杂度是 T log ⁡ n T\log n Tlogn,但是比较卡常。

代码

#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define uns unsigned
#define END putchar('\n')
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define lowbit(x) ((x)&-(x))
using namespace std;
const int MAXN=-1;
const ll INF=1e18;
inline 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;
inline 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)putchar(ptf[lpt--]^48);
	if(c>0)putchar(c);
}

inline ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
ll n,MOD,a,b,c,d;
inline ll ksm(ll a,ll b,ll mo){
	ll res=1;
	for(;b;b>>=1,a=a*a%mo)if(b&1)res=res*a%mo;
	return res;
} 
ll MD;
struct matrix{
	ll a[2][2];int n,m;matrix(){}
	matrix(int N,int M){memset(a,0,sizeof(a)),n=N,m=M;}
	matrix(ll A,ll B,ll C,ll D){
		n=m=2,a[0][0]=A,a[0][1]=B,a[1][0]=C,a[1][1]=D;
	}
	matrix operator*(const matrix&b)const{
		matrix res=matrix(n,b.m);
		for(int i=0;i<n;i++)
			for(int k=0;k<m;k++)if(a[i][k])
				for(int j=0;j<b.m;j++)
					(res.a[i][j]+=a[i][k]*b.a[k][j])%=MD;
		return res;
	}
};
inline matrix mpow(matrix a,ll b){
	matrix res=matrix(a.n,a.n);
	for(int i=0;i<a.n;i++)res.a[i][i]=1;
	for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
	return res;
}
inline ll fn(ll n,ll mod){
	matrix a=matrix(1,1,0,0),b=matrix(0,12,1,9);
	a.n=1,MD=mod,a=a*mpow(b,n);
	return a.a[0][0];
}
ll mor;
inline ll fn_gn(ll n,ll mod){
	MD=1e9+7;
	matrix a=matrix(1,1,0,0),b=matrix(0,12,1,9),c=b*b;
	for(int i=0;i<2;i++)for(int j=0;j<2;j++)c.a[i][j]/=3;
	a.n=1,MD=mod,a=a*mpow(c,n>>1)*mpow(b,n&1),mor=(a*b).a[0][0];
	return a.a[0][0];
}
int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	for(int TMA=read();TMA--;){
		n=read(),MOD=read(),a=read(),b=read(),c=read(),d=read();
		while(d)a-=b/d*c,b%=d,swap(a,c),swap(b,d);
		if(!c){
			print((fn(n,MOD)*(a%MOD+MOD)+fn(n+1,MOD)*(b%MOD+MOD))%MOD);
			continue;
		}if(c<0)c=-c;
		if(a<0)a+=((-a)/c+1)*c;
		if(!b){
			print(fn(n,MOD)*gcd(a,c)%MOD);
			continue;
		}
		ll k=gcd(b,fn_gn(n,b)),G=ksm(3,n>>1,MOD)*k%MOD;
		ll A=fn_gn(n,c*k)/k%c*a%c,B=b/k%c*mor%c;
		print(gcd(c,A+B)*G%MOD);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值