【题解】P4031 [Code+#2] 可做题2

题目链接

Better experience

Analysis

打模拟赛时没有往当前数列与最基本的斐波那契数列的关系上想。

看到斐波那契以及如此之大的数据范围,应该第一时间想到矩阵快速幂。

看到 \(a\equiv m \pmod{p}\) 应该第一时间要想到用 \(\operatorname{exgcd}\) 求解。

意识到单纯枚举 \(a2\) 是达不到正解要求的,不能由 \(a2\) 出发去判断,而是应由条件出发去统计答案。

若果直接扩展欧几里得计算的话算出来的是 \(a_k\),难以映射到 \([l,r]\) 区间内,因此将其拆为与 \(a1,a2\) 有关的式子再进行求解。

这样解法就呼之欲出了,我们将数列列出来看看:

标号:   1 2 3   4    5     6
原数列: 1 1 2   3    5     7
新数列: a b a+b a+2b 2a+3b 3a+5b

发现对于新数列第 \(k\) 个数,其值为 \(\operatorname{fib}(k-2) \cdot a + \operatorname{fib}(k-1) \cdot b\)

现在就可以化式子了。

\[\begin{aligned} a_k = \operatorname{fib}(k-2) \cdot a_1 + \operatorname{fib}(k-1) \cdot a_2 \\ \operatorname{fib}(k-2) \cdot a_1 + \operatorname{fib}(k-1) \cdot a_2 \equiv m \pmod{p} \\ \operatorname{fib}(k-1) \cdot a_2 \equiv m - \operatorname{fib}(k-2) \cdot a_1\pmod{p} \\ \operatorname{fib}(k-1) \cdot a_2 + b \cdot p = m - \operatorname{fib}(k-2) \\ \end{aligned} \]

最后用 \(\operatorname{exgcd}\) 求解即可。

CODE

#include<bits/stdc++.h>
#define int long long
using namespace std;
int l,r,k,p,m,a1;
inline int add(int x,int y){ return x + y >= p ? x + y - p : x + y; }
inline void toadd(int &x,int y){ x = add(x,y); }
inline int mul(int x,int y){ return x * y % p; }
inline int sub(int x,int y){ return x - y < 0 ? x - y + p : x - y; }
struct Mat{
	int c[2][2];
	Mat(){ memset(c,0,sizeof c); }
	Mat(int op){ for(int i = 0;i<2;++i)for(int j = 0;j<2;++j)c[i][j] = (i == j); }
	Mat(int x,int y){ c[1][0] = c[1][1] = 0, c[0][0] = x, c[0][1] = y; }
	Mat friend operator *(const Mat &a,const Mat &b){
		Mat res;
		for(int i = 0;i<2;++i)
			for(int j = 0;j<2;++j)
				for(int k = 0;k<2;++k)
					toadd(res[i][j],mul(a[i][k],b[k][j]));
		return res;
	}
	int * operator [](const int i){ return c[i]; }
	const int * operator [](const int i)const{ return c[i]; }
}bas;
Mat fpow(Mat a,int k){
	Mat res(2);
	while(k){
		if(k & 1)res = res * a;
		a = a * a;
		k >>= 1;
	}
	return res;
}
int exgcd(int a,int b,int &x,int &y){
	if(b == 0){
		x = 1, y = 0;
		return a;
	}	
	int d = exgcd(b,a%b,x,y);
	int t = x;
	x = y;
	y = t - a/b*y;
	return d;
}
//#define printf printf(">>> "),printf
void solve(){
	scanf("%lld%lld%lld%lld%lld%lld",&a1,&l,&r,&k,&p,&m);
	a1 %= p;
	Mat fibo = fpow(bas,k-2);
	
	
	int Q = m - mul(fibo[0][1],a1);
	int x,y,a = fibo[0][0],gcd = exgcd(a,p,x,y);
	
	if(Q % gcd != 0)return puts("0"),void();
	int B = p / gcd;
	int res = (x*Q/gcd%B+B)%B;
//	res + B * k ∈ [l,r]
//	res + (l - res)/B*B
	if(res > r)puts("0");
	else{
		if(l < res)printf("%lld\n",(r - res) / B + 1);
		else printf("%lld\n",(r - res) / B - (l - res - 1) / B);
	}
}
signed main(){
	bas[0][0] = bas[0][1] = bas[1][0] = 1, bas[1][1] = 0;
	int T; scanf("%lld",&T);
	while(T--)solve();
	return 0;
}
posted @ 2024-08-16 16:26  Luzexxi  阅读(11)  评论(0)    收藏  举报