[杜教筛] 51nod1220. 约数之和

来源:互联网 发布:浙江省儿童dna数据库 编辑:程序博客网 时间:2024/04/30 20:10

推一下

考虑把 ij 的质因数拆成 ij 的质因数的乘积,但是直接算会有重复。

ij 的一个质因数是 ab,其中 a|ib|j,如果满足 (a,jb)=1 的话,每个质因数就只会被枚举到一次了

那么

Sk(n)=i=1nj=1na|ib|j[(a,b)=1](ajb)k

如果k=0,反演一下就是陈老师R老师等式了

题目就是求 S1(n) ,反演一下得到

S1(n)=t=1nμ(t)ta=1ntanatb=1nti=1nbti

f(n)=ni=1inig(n)=nb=1nbi=1i

S1(n)=t=1nμ(t)tf(nt)g(nt)

μid 杜教筛, f,g分块求一下就好了

#include <cstdio>#include <iostream>#include <algorithm>#include <map>using namespace std;const int N=1000010,P=1e9+7,inv=(P+1)/6;int p[N],mu[N];inline void Pre(){  mu[1]=1;  for(int i=2;i<=1000000;i++){    if(!p[i]) p[++*p]=i,mu[i]=-1;    for(int j=1;j<=*p && 1LL*i*p[j]<=1000000;j++){      p[i*p[j]]=1;      if(i%p[j]) mu[i*p[j]]=-mu[i];      else break;    }  }  for(int i=1;i<=1000000;i++) mu[i]=(1LL*i*mu[i]+mu[i-1])%P;}map<int,int> M;inline int S(int l,int r){  return 1LL*(r-l+1)*(l+r)/2%P;}inline int Sum(int n){  if(n<=1000000) return mu[n];  if(M.count(n)) return M[n];  int ret=1;  for(int i=2,j;i<=n;i=j+1){    j=n/(n/i);    ret=(ret-1LL*S(i,j)*Sum(n/i))%P;  }  return M[n]=ret;}inline int f(int n){  int ret=0;  for(int i=1,j;i<=n;i=j+1){    j=n/(n/i);    ret=(ret+1LL*S(i,j)*(n/i))%P;  }  return ret;}inline int g(int n){  int ret=0;  for(int i=1,j;i<=n;i=j+1){    j=n/(n/i);    ret=(ret+1LL*(j-i+1)*S(1,n/i))%P;  }  return ret;}int main(){  int n,ans=0; scanf("%d",&n); Pre();  for(int i=1,j,lst=0;i<=n;i=j+1){    j=n/(n/i); int cur=Sum(j);    ans=(ans+1LL*(cur-lst)*f(n/i)%P*g(n/i))%P;    lst=cur;  }  printf("%d\n",(ans+P)%P);  return 0;}
原创粉丝点击