题意:给出斐波那契数列,
。给两个数n,m。求
题解:考虑皮萨诺周期 , 注意到 ,
并且
。于是
,
。7812500是一个不大的数,预处理前7812500项的前缀和,然后得到答案分别对
和
的余数,从而可以使用中国剩余定理得到答案。
#include <algorithm>
#include <iostream>
#define int long long
#define FOR(i, x, y) for (std::decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
using std::cin, std::cout, std::endl;
using pii = std::pair<int, int>;
const int mod = 1e9;
const int mod2 = 512;
const int mod5 = 1953125;
const int cir2 = 768;
const int cir5 = 7812500;
int bin(int x, int n, int MOD)
{
int ret = MOD != 1;
for (x %= MOD; n; n >>= 1, x = x * x % MOD)
if (n & 1)
ret = ret * x % MOD;
return ret;
}
int ex_gcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
int ret = ex_gcd(b, a % b, y, x);
y -= a / b * x;
return ret;
}
int CRT(int *m, int *r, int n)
{
if (!n)
return 0;
int M = m[0], R = r[0], x, y, d;
FOR(i, 1, n)
{
d = ex_gcd(M, m[i], x, y);
if ((r[i] - R) % d)
return -1;
x = (r[i] - R) / d * x % (m[i] / d);
R += x * M;
M = M / d * m[i];
R %= M;
}
return R >= 0 ? R : R + M;
}
int32_t main()
{
int n, m;
cin >> n >> m;
int r2 = n % cir2, r5 = n % cir5;
int fib[3] = {0, 1, 1};
int sum2 = 0, sum5 = 0;
int sum_in_cir2 = 0, sum_in_cir5 = 0;
for (int i = 0; i < cir5; i++)
{
if(i>=3)
fib[i % 3] = (fib[(i + 2) % 3] + fib[(i + 1) % 3]) % mod;
if (i < cir2)
{
(sum_in_cir2 += bin(fib[i % 3], m, mod2)) %= mod2;
}
if (i < cir5)
{
(sum_in_cir5 += bin(fib[i % 3], m, mod5)) %= mod5;
}
if (i == r2)
{
sum2=sum_in_cir2;
}
if (i == r5)
{
sum5=sum_in_cir5;
}
}
(sum2 += sum_in_cir2 * (n / cir2)%mod2) %= mod2;
(sum5 += sum_in_cir5 * (n / cir5)%mod5) %= mod5;
int mm[] = {mod2, mod5};
int rr[] = {sum2, sum5};
int ans = CRT(mm, rr, 2);
cout << ans << endl;
}
参考:
- 皮萨诺周期 (this version)
- 中国剩余定理的代码来自于 ECNU 退役队伍 F0RE1GNERS 的模板 https://github.com/zerolfx/template