LOJ 6053. 简单的函数 Min_25筛

LOJ 6053. 简单的函数 Min_25筛


传送门: https://loj.ac/p/6053

题意

有 一 个 神 奇 的 函 数 f ( x ) , 满 足 以 下 性 质 : 有一个神奇的函数f(x),满足以下性质: f(x)

  • f ( 1 ) = 1 f(1)=1 f(1)=1
  • f ( p c ) = p ⊕ c f(p^c)=p \oplus c f(pc)=pc
  • f ( a b ) = f ( a ) f ( b )    g c d ( a , b ) = 1 的 情 况 下 f(ab)=f(a)f(b)\;gcd(a,b)=1的情况下 f(ab)=f(a)f(b)gcd(a,b)=1

输 出 ∑ i = 1 n f ( i )    m o d    1 e 9 + 7 输出\sum_{i=1}^nf(i)\;mod\;1e9+7 i=1nf(i)mod1e9+7

思路

因 为 n 有 1 e 10 , 所 有 用 线 性 筛 会 T 。 因为n有1e10,所有用线性筛会T。 n1e10,线T
只 能 用 亚 线 性 筛 , 而 f 明 显 是 一 个 积 性 函 数 , 可 以 洲 阁 筛 , 当 然 , M i n _ 25 更 完 爆 它 。 只能用亚线性筛,而f明显是一个积性函数,可以洲阁筛,当然,Min\_25更完爆它。 线fMin_25

那 么 怎 么 构 造 出 一 个 M i n _ 25 筛 呢 ? 转 移 方 程 这 么 写 ? 那么怎么构造出一个Min\_25筛呢?转移方程这么写? Min_25

观 察 f ( p c ) = p ⊕ c , 对 于 一 个 质 数 p : 观察f(p^c)=p \oplus c,对于一个质数p: f(pc)=pc,p:

  1. i f ( p = 2 )    f ( p ) = 3 if(p=2) \;f(p)=3 if(p=2)f(p)=3
  2. e l s e    f ( p ) = p − 1 else\;f(p)=p-1 elsef(p)=p1

所 以 我 们 要 处 理 质 数 和 , 设 g 1 [ j ] = ∑ i = 2 j 1 , g 2 [ j ] = ∑ i = 2 j i . 所以我们要处理质数和,设g1[j]=\sum_{i=2}^j1,g2[j]=\sum_{i=2}^ji. g1[j]=i=2j1,g2[j]=i=2ji.
不 管 第 一 个 f ( 2 ) = 3 , 就 统 一 认 为 f ( p ) = p − 1 , 最 后 如 果 有 2 的 话 , a n s + 2 即 可 。 不管第一个f(2)=3,就统一认为f(p)=p-1,最后如果有2的话,ans+2即可。 f(2)=3f(p)=p12ans+2

设 p r s [ j ] 为 前 j 个 质 数 和 , p r z [ j ] 为 前 j 个 质 数 个 数 。 设prs[j]为前j个质数和,prz[j]为前j个质数个数。 prs[j]jprz[j]j

g 函 数 状 态 转 移 : g函数状态转移: g
g 1 ( j , n ) = g ( j − 1 , n ) − [ g ( j − 1 , n p j ) − p r z [ j − 1 ] ] g_1(j,n)=g(j-1,n)-[g(j-1,\frac{n}{p_j})-prz[j-1]] g1(j,n)=g(j1,n)[g(j1,pjn)prz[j1]]

g 2 ( j , n ) = g ( j − 1 , n ) − p r [ j ] ∗ ( g [ j − 1 , n p j ] − p r s [ j − 1 ] ) g_2(j,n)=g(j-1,n)-pr[j]*(g[j-1,\frac{n}{p_j}]-prs[j-1]) g2(j,n)=g(j1,n)pr[j](g[j1,pjn]prs[j1])

S ( x , y ) 的 状 态 转 移 : S(x,y)的状态转移: S(x,y)
S ( x , y ) = ∑ { g t [ i d ( x ) ] − s u m t [ j − 1 ] } + ∑ k g e y    p k e ≤ x F ( p k e ) ∗ S ( x p k e , k + 1 ) + F ( p k e + 1 ) S(x,y)=\sum\{g_t[id(x)]-sum_t[j-1]\}+\sum_{kge y\;p_k^e\leq x}F(p_k^e)*S(\frac{x}{p_k^e},k+1)+F(p_k^{e+1}) S(x,y)={gt[id(x)]sumt[j1]}+kgeypkexF(pke)S(pkex,k+1)+F(pke+1)

S ( x , y ) = ∑ { g t [ i d ( x ) ] − s u m t [ j − 1 ] } + ∑ k g e y    p k e ≤ x ( p ⊕ e ) ∗ S ( x p k e , k + 1 ) + p ⊕ ( e + 1 ) S(x,y)=\sum\{g_t[id(x)]-sum_t[j-1]\}+\sum_{kge y\;p_k^e\leq x}(p \oplus e)*S(\frac{x}{p_k^e},k+1)+p \oplus (e+1) S(x,y)={gt[id(x)]sumt[j1]}+kgeypkex(pe)S(pkex,k+1)+p(e+1)

Code

#include "bits/stdc++.h"
using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;

const int N = 1e6 + 10;

ll quick_pow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
         a = a * a % mod;
         b >>= 1;
    }
    return ans % mod;
}

namespace Min_25 {
    int is_pr[N], id1[N], id2[N], cnt;
    ll n, m, T;
    ll pr[N], prs[N], a[N], g1[N], g2[N];

    ll inv2;

    inline ll ID(ll x) {
        return x <= T ? id1[x] : id2[n / x];
    }

    inline ll calc1(ll x) {
        return (x - 1) % mod;
    }

    inline ll calc2(ll x) {
        return x % mod * (x + 1) % mod * inv2 % mod - 1;
    }

    void init() {
        cnt = m = 0;
        inv2 = quick_pow(2, mod - 2);
        T = sqrt(n + 0.5);
        for(int i = 2;i <= T; i++) {
            if(!is_pr[i]) pr[++cnt] = i, prs[cnt] = (prs[cnt - 1] + i) % mod;
            for(int j = 1;j <= cnt && i * pr[j] <= T; j++) {
                is_pr[i * pr[j]] = true;
                if(i % pr[j] == 0) break;
            }
        }

        for(ll l = 1;l <= n; l = n / (n / l) + 1) {
            a[++m] = n / l;
            if(a[m] <= T) id1[a[m]] = m;
            else id2[n / a[m]] = m;
            g1[m] = calc1(a[m]);
            g2[m] = calc2(a[m]);
        }

        for(int i = 1;i <= cnt; i++) {
            for(int j = 1;j <= m && pr[i] * pr[i] <= a[j]; j++) {
                g1[j] = (g1[j] - (g1[ID(a[j] / pr[i])] - (i - 1))) % mod;
                g2[j] = (g2[j] - pr[i] * (g2[ID(a[j] / pr[i])] - prs[i - 1]) % mod) % mod;
            }
        }
    }

    ll S(ll x, ll y) {
        if(x <= 1 || x < pr[y]) return 0;
        ll ans = (g2[ID(x)] - prs[y - 1] - (g1[ID(x)] - (y - 1)) + (y == 1 ? 2 : 0) + mod) % mod;
        for(int i = y;i <= cnt && pr[i] * pr[i] <= x; i++) {
            ll pe = pr[i];
            for(int e = 1;pe * pr[i] <= x; e++, pe *= pr[i]) {
                ans = (ans + (pr[i] ^ e) * S(x / pe, i + 1) % mod + (pr[i] ^ e + 1) % mod) % mod;
            }
        }
        return ans % mod;
    }

    ll Solve(ll x) {
        return n = x, init(), S(n, 1) + 1;
    }
}


void solve() {
    ll n; cin >> n;
    ll ans = Min_25::Solve(n);
    cout << (ans % mod + mod) % mod << endl;
}


signed main() {
    solve();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值