P5325 【模板】Min_25筛
题意:定义积性函数f(x)f(x)f(x),且f(p^k)=p^k*(p^k−1) (p是一个质数),求f(1)+f(2)+...f(n);
思路:板子题。重新打了一份装起来。
/* 定义积性函数f(x)f(x)f(x),且f(p^k)=p^k*(p^k−1)(p是一个质数),求f(1)+f(2)+...f(n); n<=1e10; 2s; */ #include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1000010; const int Mod=1000000007,inv2=500000004,inv3=333333336; struct min25 //很多部分需要long,不要搞错了 { ll p[maxn],sp1[maxn],sp2[maxn],N; ll g1[maxn],g2[maxn];int Sqr,ind1[maxn],ind2[maxn],num,tot; ll w[maxn]; bool vis[maxn]; int MOD(int x){ if(x>=Mod) x-=Mod;return x; } void prime() //得到素数,sp1,sp2 { rep(i,2,Sqr){ if(!vis[i]){ p[++num]=i; sp1[num]=MOD(sp1[num-1]+i); sp2[num]=(sp2[num-1]+1LL*i*i)%Mod; } for(int j=1;j<=num&&p[j]*i<=Sqr;j++){ vis[p[j]*i]=1; if(i%p[j]==0) break; } } } void getind() { for(ll i=1;i<=N;i++){ ll now=N/i,j=N/now,t=now%Mod; w[++tot]=now; g1[tot]=MOD(t*(t+1)/2%Mod+Mod-1); //因为我们全部都不考虑1。 g2[tot]=MOD(t*(t+1)/2%Mod*(t*2+1)%Mod*inv3%Mod+Mod-1); //*2应该不需要%Mod if(now<=Sqr) ind1[now]=tot; else ind2[j]=tot; i=j; } } void getg1g2() { rep(i,1,num){ //注意w里面的东西是递减的,所以可以滚动 for(int j=1;j<=tot&&p[i]<=w[j]/p[i];j++){ ll now=w[j]/p[i]; int k=now<=Sqr?ind1[now]:ind2[N/now]; g1[j]=MOD(g1[j]-1LL*p[i]*(g1[k]-sp1[i-1]+Mod)%Mod+Mod); g2[j]=MOD(g2[j]-1LL*p[i]*p[i]%Mod*(g2[k]-sp2[i-1]+Mod)%Mod+Mod); } } } int S(ll x,int y) { if(x<=p[y]) return 0; ll k=x<=Sqr?ind1[x]:ind2[N/x]; ll ans=(g2[k]-g1[k]+Mod-(sp2[y]-sp1[y])+Mod)%Mod; for(int i=y+1;i<=num&&p[i]*p[i]<=x;i++) { ll pe=p[i]; for(int e=1;pe<=x;e++,pe=pe*p[i]){ ll xx=pe%Mod; ans=(ans+xx*(xx-1)%Mod*(S(x/pe,i)+(e!=1)))%Mod; //这里的f(x)对应xx*(xx-1),其他函数把这里换了就行。 } } return ans%Mod; } void solve(ll n) { N=n; Sqr=sqrt(N); prime(); //筛根号部分素数。 getind(); //得到编号,以及一次前缀和,二次前缀和。 getg1g2(); //得到素数1次前缀和,二次前缀和。 printf("%d\n",MOD(S(N,0)+1)); } }T; int main() { ll N; scanf("%lld",&N); T.solve(N); return 0; }
It is your time to fight!