Address
Solution
显然是斐波那契数列。
但是递推式加入了鬼畜的条件:
我们考虑对在模
意义下的
进行讨论。
可以发现,当
时,如果是满足
最小的
,
那么
,而:
同样地,
。
于是接下去在没有模
余
的情况时,有
。
(
为斐波那契数列第
项)
考虑如果存在最小
满足
,
那么有
。
用 exgcd 求出
的逆元
,找到一个最小的
,
满足
,则
。
如果
的逆元不存在或者不存在
,则在
之后不会出现模
余
的情况。
又由于
模
的余数的最小正周期为
,所以考虑先求出最小正周期
,然后预处理出
到
的
。
然后求出
的逆元
。
定义
为:
而定义
表示满足
且
的最小的
。
由上面的推论得到,
如果
时
在
中没有出现过,则
。
其他的
都等于
。
先设初始答案为
且设
。
其中
(模
意义下),
表示
(模
意义下),
表示当前讨论
。
循环进行下面算法:
(1)如果
,那么会有
。这时候可以用矩阵乘法将
从
转移到
。注意,如果
则转移到
并输出即可。
然后
,
,
。
(2)否则
,直接转移到
即可。
这样会 TLE 。但如果
出现了重复,就意味着
出现了循环节。通过一个循环节的转移系数相同。
如果循环节长度为
,要转移
次,就只需要预处理出通过一个循环节的转移矩阵
后,求矩阵
后,剩下的
次暴力转移即可。
复杂度
。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
template <class T>
T Min(T a, T b) {return a < b ? a : b;}
typedef long long ll;
const int N = 6e6 + 5, M = 3e6 + 5, E = 4;
int k, m, ZZQ, a[N], inv[M], tot, st[M], u[M], len[M], St, Ed, vis[M];
ll n, sum;
struct matr
{
int n, m, a[E][E];
matr() {}
matr(int _n, int _m) :
n(_n), m(_m) {memset(a, 0, sizeof(a));}
friend inline matr operator * (matr a, matr b)
{
int i, j, k;
matr res = matr(a.n, b.m);
For (i, 1, res.n) For (j, 1, res.m) For (k, 1, a.m)
res.a[i][j] = (res.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % ZZQ) % ZZQ;
return res;
}
friend inline matr operator ^ (matr a, ll b)
{
int i;
matr res = matr(a.n, a.m);
For (i, 1, res.n) res.a[i][i] = 1;
while (b)
{
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
} A, D, J, V, K;
void exgcd(int a, int b, int &x, int &y)
{
if (!b) return (void) (x = 1, y = 0);
exgcd(b, a % b, y, x);
y -= a / b * x;
}
int getinv(int a, int ZZQ)
{
if (__gcd(a, ZZQ) != 1) return 0;
int x, y;
exgcd(a, ZZQ, x, y);
x = x % ZZQ + ZZQ;
return x >= ZZQ ? x - ZZQ : x;
}
matr frN(int l, int r, int st1, int st2, ll n)
{
int i;
D = matr(2, 1);
D.a[1][1] = st1; D.a[2][1] = st2;
For (i, l, r)
{
if (n <= 0) return D;
int rs = Min(n, 1ll * len[i]);
D = (A ^ rs) * D;
if (rs >= len[i] - 1) D.a[1][1] = (D.a[1][1] - 1 + ZZQ) % ZZQ;
if (rs == len[i]) D.a[2][1] = (D.a[2][1] - 1 + ZZQ) % ZZQ;
n -= rs;
}
return D;
}
int main()
{
int i;
cin >> n >> k >> ZZQ;
a[1] = a[2] = 1;
For (i, 3, 6000000)
a[i] = (a[i - 1] + a[i - 2]) % k;
For (i, 3, 6000000)
if (a[i] == 1 && a[i - 1] == 1)
{
m = i - 1; break;
}
For (i, 1, m) inv[i] = a[i] ? getinv(a[i], k) : 0;
For (i, 3, m) if (!vis[a[i]])
{
if (inv[i]) st[inv[i]] = i;
vis[a[i]] = 1;
}
memset(vis, 0, sizeof(vis));
u[1] = 1;
For (i, 2, k + 1)
{
len[i - 1] = st[u[i - 1]];
u[i] = 1ll * u[i - 1] * a[st[u[i - 1]] - 1] % k;
if (!u[i]) {St = i; Ed = -1; break;}
else if (vis[u[i]]) {St = vis[u[i]]; Ed = i - 1; break;}
vis[u[i]] = i;
}
A = matr(2, 2);
A.a[1][1] = A.a[2][1] = A.a[1][2] = 1;
For (i, 1, St - 1) sum += len[i];
matr firs = frN(1, St - 1, 1, 0, Min(n, sum));
if (n <= sum) return cout << firs.a[2][1] << endl, 0;
n -= sum; sum = 0;
if (Ed == -1) return cout << ((A ^ n) * firs).a[2][1] << endl, 0;
For (i, St, Ed) sum += len[i];
J = V = matr(3, 3);
V.a[1][1] = V.a[2][2] = V.a[3][3] = 1;
J.a[1][1] = J.a[1][2] = J.a[2][1] = 1; J.a[3][3] = 1;
K = J; K.a[1][3] = ZZQ - 1;
For (i, St, Ed)
V = J * K * (J ^ len[i] - 2) * V;
firs.n = 3; firs.a[3][1] = 1;
firs = (V ^ n / sum) * firs;
firs = frN(St, Ed, firs.a[1][1], firs.a[2][1], n % sum);
cout << firs.a[2][1] << endl;
return 0;
}