Min-25筛
写一下如何抄对板子(原理还是有看的,大概是到了看得脑壳有点疼+似乎领略到了一些东西
的程度,然后就可以心安理得地抄代码了)
step1:算g(n,j)
公式
预处理
这里\(g\)的值是\(\sum_{i=2}^{n}f'(i)\),其中\(f'(i)\)表示把\(i\)带入\(x\)为质数时\(f(x)\)的表达式,这里\(f(x)\)的表达式要求是完全积性的!(为了下一步筛出质数的\(f(x)\)之和的过程的正确性)
计算
step2:算S(n,j)
公式
计算
按照几处注释说的,把要算的式子代入即可。
取模较多,很容易寄,建议涉及取模的计算全部写成函数,就不容易错了!
整个板子
点击查看代码
namespace Min_25 {
const int MAX=4e5+5,MOD=1e9+7;
bool zs[MAX];
int tot;
ll pri[MAX];
void pre(int n) {
tot = 0;
zs[1] = true; for (int i = 2; i <= n; ++i) zs[i]=0;
for (int i = 2; i <= n; ++i) {
if (!zs[i]) pri[++tot] = i;
for (int j = 1; j <= tot && i * pri[j] <= n; ++j) {
zs[i * pri[j]] = true;
if (i % pri[j] == 0)break;
}
}
}
ll n, t, Sqr, w[MAX];
int id1[MAX], id2[MAX], g[MAX], m;
int find(ll x) {
if (x <= Sqr) return id1[x];
return id2[n / x];
}
int S(ll x, int y) {
if (x <= 1 || pri[y] > x) return 0;
int k = find(x), ret = PM(t, PS(g[k],- (y-1)));
//ret=g(x)-f(pri[i],i<y)
for (int i = y; i <= tot && pri[i] * pri[i] <= x; ++i) {
ll t1 = pri[i], t2 = 1ll * pri[i] * pri[i];
for (int e = 1; t2 <= x; ++e, t1 = t2, t2 *= pri[i])
PA(ret,PS( PM( S(x / t1, i + 1) , C(t + e - 1, e) ) , C(t + e, e + 1) ));
//注意取模!!!
//+=f(pri[i]^e)*S(n/p^e,k+1)+f(pri[i]^(e+1))
}
return ret;
}
int work(int nn, int tt) {
n = nn;
t = tt;
Sqr = sqrt(n);
pre(Sqr);
m = 0;
for (ll i = 1, j; i <= n; i = j + 1) {
j = n / (n / i);
w[++m] = n / i;
g[m]=(w[m]-1)%P;
//g[m]=f(2<=i<=w[m])
if (w[m] <= Sqr)id1[w[m]] = m;
else id2[j] = m;
}
for (int j = 1; j <= tot; ++j)
for (int i = 1; i <= m && pri[j] * pri[j] <= w[i]; ++i) {
int k = find(w[i] / pri[j]);
PA(g[i] ,- PS(g[k] ,- (j-1) ) );
//n=w[i] k=n/pri[j]
//g[n]=g'[n]-f[pri[j]]*(g'[k]-{f[pri[i]],i<j})
}
int ans = PS(S(n, 1) , 1);
for (int i = 1; i <= Sqr; i++) id1[i] = id2[i] = 0;
return ans;
}
}
例题 HDU7217
题目链接
发现\(n\)固定的时候,要算前缀和的函数满足Min-25筛的要求,可以求出\(f(n)\)。
又发现上述\(f(n)\)是关于\(n\)的不超过\(Max(e_i),(e_i为唯一分解后的各个指数)\)次多项式,所以前缀和次数加一,取前32个分别算,再做一遍前缀和,然后插值即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+5,P=1e9+7;
void PA(int& x,int y){
x+=y;
if(x>=P) x-=P;
if(x<0) x+=P;
}
int PS(int x,int y){
x+=y;
if(x>=P) x-=P;
if(x<0) x+=P;
return x;
}
int PM(int x,int y){
return 1ll*x*y%P;
}
inline int fpw(int a,int x){
int s=1;
for(;x;x>>=1,a=PM(a,a)) if(x&1) s=PM(s,a);
return s;
}
int iv[N],fc[N],fv[N],pw[N];
void init(int n){
fc[0]=pw[0]=1;
for(int i=1;i<n;i++) iv[i]=fpw(i,P-2),fc[i]=PM(fc[i-1],i),pw[i]=PM(pw[i-1],2);
fv[n-1]=fpw(fc[n-1],P-2);
for(int i=n-2;~i;i--) fv[i]=PM(fv[i+1],i+1);
}
int C(int n,int m){
if(m<0 || m>n) return 0;
return PM( fc[n],PM(fv[m],fv[n-m]) );
}
namespace Min_25 {
const int MAX=4e5+5,MOD=1e9+7;
bool zs[MAX];
int tot;
ll pri[MAX];
void pre(int n) {
tot = 0;
zs[1] = true; for (int i = 2; i <= n; ++i) zs[i]=0;
for (int i = 2; i <= n; ++i) {
if (!zs[i]) pri[++tot] = i;
for (int j = 1; j <= tot && i * pri[j] <= n; ++j) {
zs[i * pri[j]] = true;
if (i % pri[j] == 0)break;
}
}
}
ll n, t, Sqr, w[MAX];
int id1[MAX], id2[MAX], g[MAX], m;
int find(ll x) {
if (x <= Sqr) return id1[x];
return id2[n / x];
}
int S(ll x, int y) {
if (x <= 1 || pri[y] > x) return 0;
int k = find(x), ret = PM(t, PS(g[k],- (y-1)));
//ret=g(x)-f(pri[i],i<y)
for (int i = y; i <= tot && pri[i] * pri[i] <= x; ++i) {
ll t1 = pri[i], t2 = 1ll * pri[i] * pri[i];
for (int e = 1; t2 <= x; ++e, t1 = t2, t2 *= pri[i])
PA(ret,PS( PM( S(x / t1, i + 1) , C(t + e - 1, e) ) , C(t + e, e + 1) ));
//注意取模!!!
//+=f(pri[i]^e)*S(n/p^e,k+1)+f(pri[i]^(e+1))
}
return ret;
}
int work(int nn, int tt) {
n = nn;
t = tt;
Sqr = sqrt(n);
pre(Sqr);
m = 0;
for (ll i = 1, j; i <= n; i = j + 1) {
j = n / (n / i);
w[++m] = n / i;
g[m]=(w[m]-1)%P;
//g[m]=f(2<=i<=w[m])
if (w[m] <= Sqr)id1[w[m]] = m;
else id2[j] = m;
}
for (int j = 1; j <= tot; ++j)
for (int i = 1; i <= m && pri[j] * pri[j] <= w[i]; ++i) {
int k = find(w[i] / pri[j]);
PA(g[i] ,- PS(g[k] ,- (j-1) ) );
//n=w[i] k=n/pri[j]
//g[n]=g'[n]-f[pri[j]]*(g'[k]-{f[pri[i]],i<j})
}
int ans = PS(S(n, 1) , 1);
for (int i = 1; i <= Sqr; i++) id1[i] = id2[i] = 0;
return ans;
}
}
const int K=32;
int s[K];
int main()
{
init(200000);
int T; cin>>T;
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<K;i++){
s[i]=Min_25::work(m,i);
}
for(int i=1;i<K;i++) PA(s[i],s[i-1]);
int ans=0;
for(int i=1;i<K;i++){
int su=s[i];
for(int j=1;j<K;j++) if(j!=i) {
su=PM(su,PM((n+P-j)%P,fpw((i+P-j)%P,P-2)));
}
PA(ans,su);
}
cout<<ans<<endl;
}
return 0;
}