P4213 [template] Du teach sieve

Face questions

https://www.luogu.org/problem/P4213

answer

#include<cstdio>
#include<iostream>
#include<cstring>
#pragma GCC optimize(2)
#define ri register int
#define maxn 2147483647
#define maxm 3000000
#define maxk 2000
#define LL long long

using namespace std;

int p[maxm],phi[maxm],miu[maxm],k[maxm],prime[maxm],cnt=0;
bool vis[maxm];
LL S1[maxm],S2[maxk];

LL SS1[maxm],SS2[maxk];
bool vis2[maxm];

int T,N;

void getS1() {
  phi[1]=1;
  for (ri i=2;i<maxm;i++) {
    if (p[i]==0) {
      k[i]=p[i]=prime[++cnt]=i;
      phi[i]=i-1;
    }
    for (ri j=1;j<=cnt && i*prime[j]<maxm;j++) {
      k[i*prime[j]]=p[i*prime[j]]=prime[j];
      phi[i*prime[j]]=phi[i]*phi[prime[j]];
      if (prime[j]==p[i]) {
        k[i*prime[j]]*=k[i];
        phi[i*prime[j]]=phi[i/k[i]]*phi[prime[j]*k[i]];
        if (k[i*prime[j]]==i*prime[j]) phi[i*prime[j]]=i*(prime[j]-1);
        break;
      }
    }
  }
  S1[0]=0;
  for (ri i=1;i<maxm;i++) S1[i]=S1[i-1]+phi[i];


  miu[1]=1;
  for (ri i=2;i<maxm;i++) {
    if (i==p[i]) miu[i]=-1;
    else if (k[i]==i) miu[i]=0;
    else miu[i]=miu[i/k[i]]*miu[k[i]];
  }
  SS1[0]=0;
  for (ri i=1;i<maxm;i++) SS1[i]=SS1[i-1]+miu[i];
}

LL S(int n) {
  if (n<maxm) return S1[n];
  ri x=N/n;
  if (x<maxk && vis[x]) return S2[x];
  vis[x]=true;
  LL &ans=S2[x];
  ans=(LL)n*(n+1)/2;
  for (ri i=2,j;i<=n;i=j+1) {
    j=n/(n/i);
    ans-=(j-i+1)*S(n/i);
  }
  return ans;
}

LL SS(int n) {
  if (n<maxm) return SS1[n];
  ri x=N/n;
  if (x<maxk && vis2[x]) return SS2[x];
  vis2[x]=true;
  LL &ans=SS2[x];
  ans=(LL)1;
  for (ri i=2,j;i<=n;i=j+1) {
    j=n/(n/i);
    ans-=(j-i+1)*SS(n/i);
  }
  return ans;
}

int main(){
  scanf("%d",&T);
  getS1();
  for (ri i=1;i<=T;i++) {
    scanf("%d",&N);
    memset(vis,0,sizeof(vis));
    memset(vis2,0,sizeof(vis2));
    printf("%lld %lld\n",S(N),SS(N));
  }
}

 

Guess you like

Origin www.cnblogs.com/shxnb666/p/11427186.html