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_{\gcd(i,j)}=\gcd(f_i, f_j) \]

因此求 \(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;
}
posted @ 2020-11-29 17:14  limil  阅读(148)  评论(0编辑  收藏  举报