一个做法很多的题!/se
我先讲我会的做法:
首先原来的问题可以变成 a F n − 1 + b F n = 0 m o d m aF_{n-1}+bF_{n}=0\mod m aFn−1+bFn=0modm,问这个式子的答案
于是可以考虑这个式子怎么冲,我们先变成下式
− a F n − 1 = b F n m o d m -aF_{n-1}=bF_n\mod m −aFn−1=bFnmodm
如果有
− a b = F n F n − 1 m o d m -\frac{a}{b}=\frac{F_n}{F_{n-1}}\mod m −ba=Fn−1Fnmodm
就好了qaq
感觉不够,我们同时除掉三者gcd,有
a ′ F n − 1 = b ′ F n m o d m ′ a'F_{n-1}=b'F_n\mod m' a′Fn−1=b′Fnmodm′
这个式子相当优秀,我们考虑除掉三者gcd能保证至少两两gcd不会大于1,同时对于同余的两侧,一定有 g c d ( a ′ F n − 1 , m ) = g c d ( b ′ F n , m ) gcd(a'F_{n-1},m)=gcd(b'F_n,m) gcd(a′Fn−1,m)=gcd(b′Fn,m)
有这个性质我们就可以冲一下了!
我们发现 g c d ( a ′ , m ′ ) = p , g c d ( b ′ , m ′ ) = q gcd(a',m')=p,gcd(b',m')=q gcd(a′,m′)=p,gcd(b′,m′)=q
则一定有 g c d ( F n , m ′ ) = p , g c d ( F n − 1 , m ′ ) = q gcd(F_n,m')=p,gcd(F_{n-1},m')=q gcd(Fn,m′)=p,gcd(Fn−1,m′)=q
那么我们可以考虑把每一对n,n-1拿出来,然后求出这个p,q,然后再计算出 ( p , q , F n / F n − 1 m o d m / p q ) (p,q,F_{n}/F_{n-1}\mod m/pq) (p,q,Fn/Fn−1modm/pq)这个三元组插入map
然后询问的时候我们同除三者的gcd,然后算出p,q,然后算出左边那个 − a b -\frac{a}{b} −ba,再去查询一个最小的回答即可
预处理多少?循环节长度是6n的,因此不需要太多就好
注意我们mod数不同结果不同,因此还需要对于所有mod的数计算这个三元组,但是很显然我们这个mod数是m的约数
为什么m可以除p*q?
因为p,q互质
注意求逆元不能用费马小定理…
然后w还可能后面那个东西是0,因此要再去mod一次
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e5 + 7;
int n, m;
int gcd(int x, int y) {
return (y == 0) ? x : gcd(y, x % y);
}
void exgcd(int a, int b, int &x, int &y) {
if( a == 1 ) {
x = 1, y = 0;
} else exgcd(b, a % b, y, x), y -= a / b * x;
}
int inv(int a, int m) {
int x, y;
exgcd(a, m, x, y);
return (x % m + m) % m;
}
struct rec {
int x, y, z;
rec(int X = 0, int Y = 0, int Z = 0): x(X), y(Y), z(Z) {};
bool operator<(const rec &a)const {
return (x == a.x ? (y == a.y ? (z < a.z) : (y < a.y)) : x < a.x);
}
};
map<rec, int> mp[MAXN];
int f[3], cnt;
inline void upd(int x) {
int p = f[2];
f[2] = (f[2] + f[1]) % x;
f[1] = p;
++cnt;
}
inline void init() {
for(int P = 2; P <= m; ++P) {
if(m % P == 0) {
f[1] = 0;
f[2] = 1;
cnt = 1;
while(1) {
int p = gcd(f[2], P);
int q = gcd(f[1], P);
int mod = P / p / q;
int w = 1ll * (f[2] / p) * inv((f[1] / q), mod) % mod;
if(mp[P].find(rec(p, q, w)) == mp[P].end())mp[P][rec(p, q, w)] = cnt;
upd(P);
if(f[2] == 1 && f[1] == 0)break;
}
}
}
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("test.out", "w", stdout);
scanf("%d%d", &n, &m);
init();
for(int i = 1, a, b; i <= n; ++i) {
scanf("%d%d", &a, &b);
if(a == 0) {
puts("0");
continue;
} else if(b == 0) {
puts("1");
continue;
}
int P = m;
int t = gcd(a, gcd(b, P));
a /= t;
b /= t;
P /= t;
int p = gcd(a, P);
int q = gcd(b, P);
a /= p;
b /= q;
int mod = P / p / q;
int w = (mod - 1ll * a * inv(b, mod) % mod) % mod;
if(mp[P].find(rec(p, q, w)) == mp[P].end())puts("-1");
else printf("%d\n", mp[P][rec(p, q, w)]);
}
return 0;
}