BZOJ2813 - 奇妙的Fibonacci(筛法求积性函数)
题目
Fibonacci数列是这样一个数列:F1 = 1, F2 = 1, F3 = 2 . . .Fi = Fi-1 + Fi-2 (当 i >= 3)
对于某一个Fibonacci数项Fi,有多少个Fj能够整除Fi (i可以等于j);所有j的平方之和是多少。
题解
Fibonacci数列有许多性质,其中一个性质就是
因此求 \(f_j | f_i\) 可以推出 \(j | i\)。故问题变为求每个数i的约数个数 和 约数平方和。(但是要额外考虑\(f_2=1\)的情况,因为前面那个条件不是充要条件)
i的约数个数 和 约数平方和 都是积性函数,而积性函数基本都可以用线性筛筛出来。关键在于若枚举的质数p有i%p==0(即p为i*p的平方因子)时的处理。
求约数个数
令\(f(i)\)为i约数个数,\(num(i)\)为i最小质因数对应的次方数。
若\(i = p_1^{c_1}p_2^{c_2}...p_k^{c_k}\),那么\(f(i) = \prod (c_i+1)\),为积性函数。
若i%p==0,p为i*p的最小质因数,也是i*p的平方因子
\(num(i*p)=num(i)+1\)
\(f(i*p)=\frac{f(i)}{num(i)}\cdot (num(i)+1)\)
求约束平方和
令\(f(i)\)为i约数平方和,\(g(i)\)为i最小质因数p的(\(p^{2\cdot 0}+p^{2\cdot 1}+...+p^{2\cdot k}\))。
若\(i = p_1^{c_1}p_2^{c_2}...p_k^{c_k}\),那么\(f(i) = \prod (p^{2\cdot 0}+p^{2\cdot 1}+...+p^{2\cdot c_i})\),为积性函数。
若i%p==0,p为i*p的最小质因数,也是i*p的平方因子
\(g(i \cdot p)=g(i) \cdot p^2 + 1\)
\(f(i \cdot p)=\frac{f(i)}{g(i)}\cdot (g(i) \cdot p^2 +1)\)
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const ll N = 1e7 + 10;
const ll M = 1e9 + 7;
const double eps = 1e-5;
bool vis[N];
ll prime[N];
ll cnt;
ll num[N]; // 最小约数的k
ll g[N]; // 最小约数2k方和
ll f1[N]; // 所有约数的个数
ll f2[N]; // 所有约数的平方和
void init() {
f1[1] = f2[1] = num[1] = 1;
for(ll i = 2; i < N; i++) {
if(!vis[i]) {
num[i] = 1;
g[i] = i * i + 1;
f1[i] = 2;
f2[i] = g[i];
vis[i] = 1;
prime[cnt++] = i;
}
for(ll j = 0; j < cnt && prime[j] * i < N; j++) {
ll p = prime[j];
vis[p * i] = 1;
if(i % p == 0) {
num[p * i] = num[i] + 1;
f1[p * i] = f1[i] / num[p * i] * (num[p * i] + 1);
g[p * i] = g[i] * p * p + 1;
f2[p * i] = f2[i] / g[i] * g[p * i];
break;
} else {
f1[p * i] = 2 * f1[i];
num[p * i] = 1;
f2[p * i] = f2[p] * f2[i];
g[p * i] = p * p + 1;
}
}
}
}
int main() {
IOS;
init();
ll q;
cin >> q;
ll tq, a, b, c;
cin >> tq >> a >> b >> c;
ll ans1 = 0;
ll ans2 = 0;
for(ll i = 1; i <= q; i++) {
ll p = tq;
tq = (tq * a + b) % c + 1;
if(p % 2) {
ans1 = (ans1 + f1[p] + 1) % M;
ans2 = (ans2 + f2[p] + 4) % M;
} else {
ans1 = (ans1 + f1[p]) % M;
ans2 = (ans2 + f2[p]) % M;
}
ans1 %= M;
ans2 %= M;
}
cout << ans1 << endl;
cout << ans2 << endl;
}