[杜教筛] HDU5608. function

裸题

S(n)=i=1n(i23i+2)i=2nS(ni)

(f1)(n)=n23n+2

f(n)=(fϵ)(n)=(fμ1)(n)=d|n(d23d+2)μ(nd)

O(nlnn) 预处理后上杜教筛

#include 
#include 
#include 
#include 

using namespace std;

const int P=1e9+7,inv=(P+1)/6;

map<int,int> S;

int t,n,f[1000010];
int p[1000010],mu[1000010];

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++){
    int cur=(1LL*i*i-3*i+2)%P;
    for(int j=i;j<=1000000;j+=i)
      f[j]=(f[j]+1LL*cur*mu[j/i])%P;
  }
  for(int i=1;i<=1000000;i++)
    f[i]=(f[i]+f[i-1])%P;
}

int Sum(int n){
  if(n<=1000000) return f[n];
  if(S.count(n)) return S[n];
  int &ret=S[n];
  ret=(1LL*n*(n+1)%P*(2*n+1)%P*inv-3LL*n*(n+1)/2+2*n)%P;
  for(int i=2,j;i<=n;i=j+1){
    j=n/(n/i);
    ret=(ret-1LL*(j-i+1)*Sum(n/i))%P;
  }
  return ret;
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  Pre(); scanf("%d",&t);
  while(t--){
    scanf("%d",&n);
    printf("%d\n",(P+Sum(n))%P);
  }
}

你可能感兴趣的:(杜教筛)