1 条题解
-
0
自动搬运
来自洛谷,原作者为

Tiw_Air_OAO
定义。专注。存在。搬运于
2025-08-24 22:28:48,当前版本为作者最后更新于2021-02-07 19:08:39,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
分享一个(自认为)比较简单的做法:
先特判 与 的情况。
定义 为第 个斐波那契数(这里取 ),则题目等价于 。
关于这一点,可以考虑 “转移矩阵中的值总可以写成斐波那契数”,那么第 项即 。
一个自然的想法是变成 ,然而由于 可以是合数,所以不一定互质。
考虑移项,并给 同时除掉 ,得到:
注意此时 仍可以 。
由于 ,此时应有 以及 。
且此时等式两边以及模数同除 即可实现互质。
那么在 处塞个三元组 ,用
std::map或 hash 维护,之后直接查询即可。
斐波那契数的循环节是 的(可以百度得到更进一步的分析)。
那么该算法预处理的复杂度为 ,其中 是因子和,查询的复杂度是 。
我的代码实现用的是
std::map,因此跑得比较慢。如果用 hash 可能会快一点。#include <bits/stdc++.h> const int N = 200000; 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 node{ int x, y, z; friend bool operator < (const node &a, const node &b) { return (a.x == b.x) ? ((a.y == b.y) ? (a.z < b.z) : (a.y < b.y)) : (a.x < b.x); } }; int m; std::map<node, int>mp[N + 5]; void init() { for(int i=2;i<=m;i++) if( m % i == 0 ) { int x = 1, y = 0; for(int j=0;;j++) { if( x && y ) { int d1 = gcd(i, x), d2 = gcd(i, y), m1 = i / d1 / d2; int k = (int)(1ll * (y / d2) * inv((x / d1), m1) % m1); if( !mp[i].count((node){k, d1, d2}) ) mp[i][(node){k, d1, d2}] = j; } int x1 = x; x = y, y = (x1 + y) % i; if( x == 1 && y == 0 ) break; } } } int main() { // freopen("fib.in", "r", stdin); // freopen("fib.out", "w", stdout); int n; scanf("%d%d", &n, &m), init(); for(int i=1,a,b;i<=n;i++) { scanf("%d%d", &a, &b), b = (m - b) % m; if( a == 0 ) {puts("0"); continue;} if( b == 0 ) {puts("1"); continue;} int d = gcd(gcd(a, b), m), m1 = m / d; a /= d, b /= d; int p = gcd(a, m1), q = gcd(b, m1), m2 = m1 / p / q; a /= p, b /= q; int k = (int)(1ll * a * inv(b, m2) % m2); if( mp[m1].count((node){k, q, p}) ) printf("%d\n", mp[m1][(node){k, q, p}]); else printf("-1\n"); } }
- 1
信息
- ID
- 6470
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者