Luogu P5325 【模板】Min_25筛

题链

\[f(p)=p^2-p \]

对于质数可以分开求
然后min25板子

#include<bits/stdc++.h>
#define ll long long
const int p=1e9+7,inv2=500000004,inv3=333333336;
using namespace std;

const int N=1e6+5;
ll n,w[N]; 
bool fl[N];
int s,cnt,pri[N],s1[N],s2[N],id1[N],id2[N],g1[N],g2[N];
int mo(int x) {
	return x>=p?x-p:x;
}
void init() {
	s=sqrt(n);
	for(int i=2;i<=s;i++) {
		if(!fl[i]) {
			pri[++cnt]=i;
			s1[cnt]=(s1[cnt-1]+(ll)i*i)%p;
			s2[cnt]=mo(s2[cnt-1]+i);
		}
		for(int j=1;j<=cnt&&(ll)pri[j]*i<=s;j++) {
			fl[pri[j]*i]=1;
			if(i%pri[j]==0) break;
		}
	}
	int num=0;
	for(ll i=1,r;i<=n;i=r+1) {
		ll t=n/i; r=n/t; w[++num]=t;
		if(t<=s) id1[t]=num;
			else id2[n/t]=num;
		t%=p;
		g1[num]=(t*(t+1)%p*inv2%p*(t+t+1)%p*inv3-1+p)%p;
		g2[num]=(t*(t+1)%p*inv2-1+p)%p;
	}
	for(int j=1;j<=cnt;j++) {
		for(int i=1;i<=num&&(ll)pri[j]*pri[j]<=w[i];i++) {
			int k=(w[i]/pri[j]<=s?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])]);
			g1[i]=mo((g1[i]-(ll)pri[j]*pri[j]%p*(g1[k]-s1[j-1]))%p+p);
			g2[i]=mo((g2[i]-(ll)pri[j]*(g2[k]-s2[j-1]))%p+p);
		}
	}
}
int S(ll u,int j) {
	if(u<=1||u<pri[j]) return 0;
	int k=(u<=s?id1[u]:id2[n/u]);
	int ret=((ll)g1[k]-g2[k]-s1[j-1]+s2[j-1]+p+p)%p;
	for(int i=j;i<=cnt&&(ll)pri[i]*pri[i]<=u;i++) {
		ll t=pri[i];
		for(int e=1;t<=u;e++,t*=pri[i]) {
			ret=(ret+(ll)(S(u/t,i+1)+(e!=1))*(t%p)%p*((t-1)%p))%p;
		}
	}
	return ret;
}
int main() {
	scanf("%lld",&n);
	init();
	printf("%d\n",mo(1+S(n,1)));
	return 0;
}
posted @ 2021-06-02 23:33  wwwsfff  阅读(41)  评论(0编辑  收藏  举报