Min_25

题目背景

模板题,无背景。

题目描述

定义积性函数f(x),且\(f(p^k)= p^k (p^k − 1)\)(p是一个质数),求
\[ \huge \displaystyle \sum_{i=1}^{n}f(x) \]
对109+7取模。

输入格式

一行一个整数n。

输出格式

一个整数表示答案。

输入输出样例

输入 #1

10

输出 #1

263

输入 #2

1000000000

输出 #2

710164413

说明/提示

\(n <= 1e10\)

Min_25筛是个神奇的东西 , 在这写一下我的理解, 其实背过就好了。。。。

首先 Min_25筛 的适用范围是\(f(p) 和 f(p^k)\) 在p是质数是比较好求 , 且n很大。

Pre

将 n 整除分块作为 , 以后的 dp 用到的值。

step 1

计算质数的贡献

类似dp , 设\(g(n , j)\) 表示在前n个数中 , 最小质因子 >= \(P_j\) 的数 ,或者是质数的 f 的和。
\[ g(n , j) = g(n , j - 1) \ \ \ \ \ \ \ \ \ \ \ (p_j^2 > n) \\ g(n , j) = g(n , j - 1) - f(p_j) * (g(\left\lfloor\frac{n}{p_j}\right\rfloor , j - 1) - \sum_{i=1}^{j-1}f(P_j)) \ \ \ \ P_j^2 <= n \]
\(g(n , 0)\) 也就是所有,数的 f 值

step 2

计算合数的贡献

\(s(n , j)\) 表示 最小质因子 >= \(P_j\) 的 f 值之和。

那他有两部分构成 一部分是质数 , 另一部分是合数。

质数的可以是 \(\huge g(n , |P|) - \displaystyle \sum_{i=1}^{j-1}f(P_i)\)

合数的就暴力枚举 , 最小质因子以及他的次数
\[ S(n , j) = g(n , |P|) - \sum_{i=1}^{j-1}f(P_i) + \sum_{k=j}^{P_k^2 <=n}\sum_{e=1}^{P_K^{e+1}<=n}S(\left\lfloor\frac{n}{P_k^e}\right\rfloor , k + 1) * f(P_k^e) + f(P_k^{e+1}) \]

巨佬的讲解

其实吧就是为了存个代码

#include
#include
#include
using namespace std;
#define int long long 
const int N = 1e6+100;
const int mod = 1e9+7;
const long long inv6 = 166666668;
const long long inv2 = 500000004;
#define RQ puts("RQ");
long long n;
int m , Sqr , tot;
int vis[N] , id1[N] , id2[N];
long long sp[N] , sp2[N] , g[N] , h[N] , w[N] , prime[N];
inline int id(long long val) { return val <= Sqr ? id1[val] : id2[n / val]; }

void Init(int maxn)
{
    for(int i = 2 ; i <= maxn ; ++i) // sp[tot]!!!
    {
        if(vis[i] == 0) prime[++tot] = i , sp[tot] = (sp[tot-1] + i) % mod , sp2[tot] = (sp2[tot-1] + 1LL * i * i % mod) % mod;
        for(int j = 1 ; j <= tot && prime[j] * i <= maxn ; ++j)
        {
            vis[i * prime[j]] = 1;
            if(i * prime[j] == 0) break;
        }
    }
    return ;
}

long long ksm(int a , int k)
{
    long long ans = 1;
    for( ; k ; k >>= 1 , a = 1LL * a * a % mod)
        if(k & 1) ans = ans * a % mod;
    return ans;
}

long long solve(long long n , int p)
{
    if(n <= 1 || prime[p] > n) return 0;
    int k = id(n);
    long long res = (h[k] - sp2[p-1]) % mod - (g[k] - sp[p-1]) % mod;
    res = (res % mod + mod) % mod;
    for(int i = p ; i <= tot && 1LL * prime[i] * prime[i] <= n ; ++i)
    {
        long long p1 = prime[i] , p2 = 1LL * prime[i] * prime[i];
        for(int e = 1 ; p2 <= n ; e++ , p1 = p2 , p2 *= prime[i])
            res = (res + (solve(n / p1 , i + 1) * ((p1%mod) * (p1%mod - 1) % mod) % mod + ((p2%mod) * (p2%mod - 1) % mod)) % mod) % mod;
    }
    return (res%mod+mod)%mod;
}

signed main()
{
    cin >> n; Sqr = sqrt(n); Init(Sqr);
    for(long long i = 1 ; i <= n ; i = (n / w[m]) + 1)
    {
        w[++m] = n / i;
        if(w[m] <= Sqr) id1[w[m]] = m; else id2[n / w[m]] = m;
        g[m] = ((w[m] + 2) % mod * ((w[m] - 1) % mod)) % mod; 
        g[m] = g[m] * inv2 % mod;
        h[m] = ((w[m] % mod * ((w[m] + 1) % mod)) % mod * ((w[m] * 2 % mod + 1) % mod)) % mod; 
        h[m] = h[m] * inv6 % mod; h[m] = ((h[m] - 1) % mod + mod) % mod; // ----1111
    }
    for(int j = 1 ; j <= tot ; ++j)
        for(int i = 1 ; i <= m && 1LL * prime[j] * prime[j] <= w[i] ; ++i)
        {
            int k = id(w[i] / prime[j]);
            g[i] = (g[i] - 1LL * prime[j] * (g[k] - sp[j-1]) % mod) % mod; 
            g[i] = (g[i] % mod + mod) % mod;
            h[i] = (h[i] - 1LL * prime[j] * prime[j] % mod * (h[k] - sp2[j-1]) % mod) % mod; 
            h[i] = (h[i] % mod + mod) % mod;
        }
    long long ans = solve(n , 1) + 1;
    printf("%lld\n" , ans % mod);
    return 0;
}
/*
9999998765 
38860607
*/

你可能感兴趣的:(Min_25)