Min_25
Posted r-q-r-q
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(leftlfloorfrac{n}{p_j}
ight
floor , 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(leftlfloorfrac{n}{P_k^e}
ight
floor , k + 1) * f(P_k^e) + f(P_k^{e+1})
]
其实吧就是为了存个代码
#include<iostream>
#include<cstdio>
#include<cmath>
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
" , ans % mod);
return 0;
}
/*
9999998765
38860607
*/
以上是关于Min_25的主要内容,如果未能解决你的问题,请参考以下文章