[luogu P5325][模板]Min_25筛

Address

Luogu #5325

Solution

  • 记 \(p_i\) 表示第 \(i\) 小的质数(\(p[0]=1\)),\(s1[x]=\sum_{i=1}^{x}p[x],s2[x]=\sum_{i=1}^{x}p[x]^2\)。
  • 记 \(g1(x,i)\) 为:\[\sum_{j=1}^{x}[j是质数或j的最小质因子大于p_i]j\]
  • 记 \(g2(x,i)\) 为:\[\sum_{j=1}^{x}[j是质数或j的最小质因子大于p_i]j^2\]
  • 因为 \(n\) 以内的合数的最小质因子为 \(O(\sqrt n)\),所以第二维的 \(i\) 满足:\(p_i^2≤n\)。
  • 记 \(s(x,y)\) 为:\[\sum_{j=1}^{x}[j的最小质因子大于p_y]j^2-j\]
  • 那么显然有: \[ans=S(x,y)+1\]
  • 假设我们已经求得了所有的 \(g1(x,i),g2(x,i)\)。
  • 考虑如何求 \(s(x,y)\):
  • 我们分别考虑质数与合数对答案的贡献。
  • 对于质数,记 \(\sqrt n\) 以内的质数个数为 \(c\),我们要求的就是:\[res=\sum_{j=y+1}^{c}p_j^2-p_j\]
  • 我们把它转换为两个前缀和相减的形式(前 \(c\) 个的贡献 \(-\) 前 \(j\) 个的贡献),并且利用上 \(g1,g2\),那么有:\[res=g2(x,c)-g1(x,c)-(s2[y]-s1[y])\]
  • 对于合数,有最小质因子大于 \(p_y\) 的限制。
  • 我们枚举 \(i,j\),并计算所有满足以下条件的合数 \(a\) 对答案的贡献:
    1.\(a\) 的最小质因子为 \(p_i\)。
    2.\(a\) 可以分解出 \(j\) 个 \(p_i\)。
  • 我们把每个合法的 \(a\) 都分解出因数 \(p_i^j\),记 \(b\) 为分解后的 \(a\),那么 \(b\) 要满足条件:
    1.\(b\) 的最小质因子大于 \(p_i\) 或 \(b=1\)
    2.\(b≤\lfloor\frac{x}{p_i^j}\rfloor\)。
  • 那么我们就得出了递推式:\[s(x,y)=res-\sum_{i=y+1}^{c}\sum_{j=1,p_i^j≤x}f(p_i^j)*(s(\lfloor\frac{x}{p_i^j}\rfloor,i)+[j=1])\]
  • 现在还有一个问题,就是求 \(g1,g2\)。
  • 我们可以这样求 \(g1\)(\(g2\) 同理):
  • 先让 \(g1(x,i)=g1(x,i-1)\),接着要减去所有满足最小质因子等于 \(p_i\)的合数的贡献。
  • 我们还是把这些合数分解出因数 \(p_i\),然后分解后的数 \(d\) 要满足以下条件:
    1.\(d\) 的最小质因子大于 \(p_{i-1}\)。
    2.\(d≤\lfloor\frac{x}{p_i}\rfloor\)。
  • 显然有:\[g1(x,i)=g1(x,i-1)-p_i(g1(\lfloor\frac{x}{p_i}\rfloor,i-1)-s1[i-1])\]
  • 然后还有一个问题就是 \(g1,g2,s\) 的第一维可能到 \(O(n)\) 级别,需要离散化。
  • 显然第一维只可能是某个 \(\lfloor\frac{n}{i}\rfloor\) 的值。
  • 那么当 \(x≤\sqrt n\)时,记 \(id1[x]\) 表示 \(x\) 离散化后的值。
  • 否则,记 \(id2[n/x]\) 表示 \(x\) 离散化后的值。

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int e = 1e6 + 5, mod = 1e9 + 7;
ll g1[e], g2[e], n, s1[e], s2[e], a[e];
bool bo[e];
int cnt, p[e], tot, id1[e], id2[e], s, inv6;

inline int plu(int x, int y)
{
    (x += y) >= mod && (x -= mod);
    return x;
}

inline int sub(int x, int y)
{
    (x -= y) < 0 && (x += mod);
    return x;
}

inline int ksm(int x, int y)
{
    int res = 1;
    while (y)
    {
        if (y & 1) res = (ll)res * x % mod;
        y >>= 1;
        x = (ll)x * x % mod;
    }
    return res;
}

inline int calc1(ll x)
{
    x %= mod;
    return (ll)x * (x + 1) / 2 % mod;
}

inline int calc2(ll x)
{
    x %= mod;
    return (ll)x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}

inline void init()
{
    inv6 = ksm(6, mod - 2); s = sqrt(n);
    ll i, j;
    for (i = 1; i <= n; i = j + 1)
    {
        a[++tot] = n / i;
        j = n / a[tot];
        g1[tot] = sub(calc1(a[tot]), 1);
        g2[tot] = sub(calc2(a[tot]), 1);
        if (a[tot] <= s) id1[a[tot]] = tot;
        else id2[n / a[tot]] = tot;
    }
}

inline void sieve()
{
    int i, j;
    for (i = 2; i <= s; i++)
    {
        if (!bo[i])
        {
            p[++cnt] = i;
            s1[cnt] = plu(s1[cnt - 1], i);
            s2[cnt] = plu(s2[cnt - 1], (ll)i * i % mod);
        }
        for (j = 1; j <= cnt && i * p[j] <= s; j++)
        {
            bo[i * p[j]] = 1;
            if (i % p[j] == 0) break;
        }
    }
}

inline void solve_g()
{
    int i, j;
    for (i = 1; i <= cnt; i++)
    {
        for (j = 1; j <= tot; j++)
        if ((ll)p[i] * p[i] <= a[j])
        {
            ll x = a[j], y = x / p[i];
            int k = y <= s ? id1[y] : id2[n / y], z = x <= s ? id1[x] : id2[n / x];
            g1[z] = sub(g1[z], (ll)p[i] * sub(g1[k], s1[i - 1]) % mod);
            g2[z] = sub(g2[z], (ll)p[i] * p[i] % mod * sub(g2[k], s2[i - 1]) % mod);
        }
    }
}

inline int dfs(ll x, int y)
{
    if (p[y] >= x) return 0;
    int i, j, k = x <= s ? id1[x] : id2[n / x];
    int res = sub(sub(g2[k], g1[k]), sub(s2[y], s1[y]));
    ll pj;
    for (i = y + 1; i <= cnt && (ll)p[i] * p[i] <= x; i++)
    for (j = 1, pj = p[i]; pj <= x; j++, pj = pj * p[i])
    {
        int f = pj % mod;
        f = (ll)f * sub(f, 1) % mod;
        res = plu(res, (ll)f * plu(dfs(x / pj, i), j != 1) % mod);
    }
    return res;
}

int main()
{
    cin >> n; init(); sieve(); solve_g();
    cout << plu(dfs(n, 0), 1) << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/cyf32768/p/12196141.html

时间: 2024-10-09 07:20:16

[luogu P5325][模板]Min_25筛的相关文章

LG5325 【模板】Min_25筛

P5325 [模板]Min_25筛 题目背景 模板题,无背景. 题目描述 定义积性函数$f(x)$,且$f(p^k)=p^k(p^k-1)$($p$是一个质数),求 $$\sum_{i=1}^n f(x)$$ 对$10^9+7$取模. 输入输出格式 输入格式: 一行一个整数$n$. 输出格式: 一个整数表示答案. 输入输出样例 输入样例#1: 复制 10 输出样例#1: 复制 263 输入样例#2: 复制 1000000000 输出样例#2: 复制 710164413 说明 $f(1)=1,f(

P4213 【模板】杜教筛(Sum) min_25筛

\(\color{#0066ff}{ 题目描述 }\) 给定一个正整数\(N(N\le2^{31}-1)\) 求 \(ans_1=\sum_{i=1}^n\varphi(i)\) \(ans_2=\sum_{i=1}^n \mu(i)\) \(\color{#0066ff}{输入格式}\) 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 \(\color{#0066ff}{输出格式}\) 一共T行,每行两个用空格分隔的数ans1,ans2 \(\c

[luogu P3384] [模板]树链剖分

[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #inc

SP34096 DIVCNTK - Counting Divisors (general) min_25筛

\(\color{#0066ff}{ 题目描述 }\) \(σ_0(i)\) 表示\(i\) 的约数个数 求\(S_k(n)=\sum_{i=1}^n\sigma_0(i^k)\mod 2^{64}\) \(\color{#0066ff}{输入格式}\) 第一行一个T为数据组数 接下来每组数据一个n,一个k \(\color{#0066ff}{输出格式}\) 每个询问输出一行 \(\color{#0066ff}{输入样例}\) 5 1 3 2 3 3 3 10 3 100 3 \(\color{

51Nod1222 最小公倍数计数 数论 Min_25 筛

原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1222.html 题意 给定 $a,b$, 求 $$\sum_{n=a}^b \sum_{i=1}^n \sum_{j=1}^i [{\rm lcm } (i,j) = n]$$ $$a,b\leq 10^{11}$$ $${\rm Time \ Limit } = 6s$$ 题解 本题做法很多. Min_25 筛 先差分一下,转化成求前缀和. 先把原题的统计无序数对转化成统计有序数对,最终 $an

UOJ188. 【UR #13】Sanrd [min_25筛]

传送门 思路 也可以算是一个板题了吧qwq 考虑min_25筛最后递归(也就是DP)的过程,要枚举当前最小的质因子是多少. 那么可以分类讨论,考虑现在这个质因子是否就是次大质因子. 如果不是,那么就是\(S(n/p,k+1)\):如果是,那么剩下的必定是一个更大的质数,那么就需要知道一段区间内有多少个质数. 质数个数显然可以min_25筛给搞出来. 于是就做完了. 代码 #include<bits/stdc++.h> clock_t t=clock(); namespace my_std{ u

ZOJ The Sum of Unitary Totient (Min_25筛)

题意: 给你一个函数f(n)=(p1a1-1)(p2a2-1)...(prar-1) ,n=p1a1p2a2...prar  求\[\sum\limits_{i = 1}^n {f(i)} \],\[n <  = 1e9\] 思路: \[f(p) = p - 1,f({p^k}) = {p^k} - 1\],直接用min_25筛就可以了,按道理来讲我感觉min_25筛是稳过的,但我交了几十次才过,要不是在网上看到有人用min_25筛过了我还以为我想错了 #include<bits/stdc++

模板:筛素数法

参考:http://blog.csdn.net/liukehua123/article/details/5482854 1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false. 2.然后: for( i=3; i<=sqrt(n); i+=2 ) {   if(prime[i]) for( j=i+i; j<=n; j+=i ) prime[j]=false; } 3.最后输出bool数组中的值为true的单元的下标,