• [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]j2$$
    • 因为 \(n\) 以内的合数的最小质因子为 \(O(\sqrt n)\),所以第二维的 \(i\) 满足:\(p_i^2≤n\)
    • \(s(x,y)\) 为:$$\sum_{j=1}{x}[j的最小质因子大于p_y]j2-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_j2-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_ij≤x}f(p_ij)*(s(\lfloor\frac{x}{p_ij}\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;
    }
    
  • 相关阅读:
    JavaScript-创建日志调试对象(面向对象实例)
    公有属性 公有方法(原型方法) 私有属性 私有方法 特权方法 静态属性 静态方法 对象字面量创建
    JS库创建
    无post按钮提交表单
    当浏览器窗口大小改变时,设置显示内容的高度
    单元测试(qunit)
    HTML定位(滚动条、元素,视口)定位
    document.compatMode(判断当前浏览器采用的渲染方式)
    jquery自定义方法
    jQuery选择器总结
  • 原文地址:https://www.cnblogs.com/cyf32768/p/12196141.html
Copyright © 2020-2023  润新知