【题解】P4031 [Code+#2] 可做题2
题目链接。
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;
}

浙公网安备 33010602011771号