Loj 6053. 简单的函数(Min_25筛)

Loj 6053. 简单的函数(Min_25筛)

题目大意

有一积性函数,当p为质数时有
f ( p c ) = p   X O R   c f(p^c)=p\ XOR\ c f(pc)=p XOR c
∑ i = 1 n f ( i )   m o d   ( 1 0 9 + 7 ) \sum_{i=1}^nf(i)\ mod\ (10^9+7) i=1nf(i) mod (109+7)

解题思路

对于 f ( p ) f(p) f(p)只有当p为2时其值为3,其余情况,为p-1。不妨令其为素数时即有 f ( p ) = p − 1 f(p)=p-1 f(p)=p1则满足自变量为素数时,函数值为多项式,则可以min25筛求之

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int size = 1e6 + 5;
LL n, s;
LL p[size];
bool prime[size];
unordered_map<LL, int> ID;
LL pre[size];
LL num[size];
LL h1[size], h0[size];
int tol, tot;
LL get_g(LL x, int k) {
    if (x <= 1 || p[k] > x)
        return 0;
    LL ans = (h1[ID[x]] - h0[ID[x]] + mod - (pre[k - 1] - (k - 1)) + mod) % mod;
    if (k == 1)
        ans += 2;
    while (1LL * p[k] * p[k] <= x && k <= tol) {
        LL pk = p[k], t = p[k];
        for (int e = 1; t * pk <= x; e++, t = t * pk) {
            ans = (ans + (pk ^ e) % mod * get_g(x / t, k + 1) % mod + (pk ^ (e + 1)) % mod) % mod;
        }
        k++;
    }
    return ans % mod;
}
void get_h() {
    s = sqrt(n);
    while (s * s <= n) s++;
    while (s * s > n) s--;
    for (int i = 1; i <= s; i++) prime[i] = true;
    for (int i = 2; i <= s; i++) {
        if (prime[i]) {
            p[++tol] = i;
            pre[tol] = (pre[tol - 1] + i) % mod;
        }
        for (int j = 1; j <= tol && p[j] * i <= s; j++) {
            prime[p[j] * i] = false;
            if (i % p[j] == 0)
                break;
        }
    }
    for (int i = 1; i <= s; i++) {
        num[++tot] = i;
        ID[i] = tot;
    }
    for (int i = s; i >= 1; i--)
        if (n / i > s) {
            num[++tot] = n / i;
            ID[n / i] = tot;
        }
    for (int i = 1; i <= tot; i++) h0[i] = h1[i] = num[i] % mod;
    for (int i = 1; i <= tot; i++) {
        h1[i] = h1[i] * (h1[i] + 1) / 2 % mod;
        h1[i] = (h1[i] - 1 + mod) % mod;
        h0[i] = (h0[i] - 1 + mod) % mod;
    }
    int x = 1;
    for (int j = 1; j <= tol; j++) {
        while (num[x] < p[j] * p[j]) x++;
        for (int i = tot; i >= x; i--) {
            h1[i] = (h1[i] - 1LL * p[j] * (h1[ID[num[i] / p[j]]] - pre[j - 1]) % mod + mod) % mod;
            h0[i] = (h0[i] - (h0[ID[num[i] / p[j]]] - (j - 1)) % mod + mod) % mod;
        }
    }
}
int main() {
    scanf("%lld", &n);
    get_h();
    printf("%lld\n", (get_g(n, 1) + 1) % mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值