• [BZOJ3944]Sum


    题目大意:
      对于给定的$n(n<2^{31})$,求$sum_{i=1}^nvarphi(i)$和$sum_{i=1}^nmu(i)$。

    思路:
      $sum_{i=1}^nvarphi(i)$同BZOJ4805。
      设$S(n)=sum_{i=1}^nmu(i)$。
      因为$sum_{d|n}mu(d)=[n=1]$,$S(n)=sum_{i=1}^n([i=1]-sum_{d|i,d<i}mu(d))=1-sum_{i=2}^nS(lfloorfrac ni floor)$。
      线性筛预处理$S$的前$n^{frac23}$项,剩下的数论分块计算,用哈希表保存已经算过的值,记忆化搜索即可。时间复杂度$O(n^{frac23})$。

    细节:
      两个询问必须写在一个函数里,否则会TLE。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<hash_map>
     4 typedef long long int64;
     5 inline int getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register int x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 const int N=1664511,M=125640;
    13 bool vis[N];
    14 int m,mu[N],phi[N],p[M];
    15 int64 s_mu[N],s_phi[N];
    16 __gnu_cxx::hash_map<int,std::pair<int64,int64> > map;
    17 inline void sieve() {
    18     phi[1]=mu[1]=s_phi[1]=s_mu[1]=1;
    19     for(register int i=2;i<N;i++) {
    20         if(!vis[i]) {
    21             p[++p[0]]=i;
    22             mu[i]=-1;
    23             phi[i]=i-1;
    24         }
    25         for(register int j=1;j<=p[0]&&i*p[j]<N;j++) {
    26             vis[i*p[j]]=true;
    27             if(i%p[j]==0) {
    28                 mu[i*p[j]]=0;
    29                 phi[i*p[j]]=phi[i]*p[j];
    30                 break;
    31             }
    32             mu[i*p[j]]=-mu[i];
    33             phi[i*p[j]]=phi[i]*phi[p[j]];
    34         }
    35         s_mu[i]=s_mu[i-1]+mu[i];
    36         s_phi[i]=s_phi[i-1]+phi[i];
    37     }
    38 }
    39 inline std::pair<int64,int64> calc(const int64 &n) {
    40     if(n<N) return std::make_pair(s_phi[n],s_mu[n]);
    41     if(map.count(n)) return map[n];
    42     std::pair<int64,int64> ans=std::make_pair((int64)n*(n+1)/2,1);
    43     for(register int64 l=2,r;l<=n;l=r+1) {
    44         r=n/(n/l);
    45         std::pair<int64,int64> tmp=calc(n/l);
    46         ans.first-=tmp.first*(r-l+1);
    47         ans.second-=tmp.second*(r-l+1);
    48     }
    49     return map[n]=ans;
    50 }
    51 int main() {
    52     sieve();
    53     for(register int T=getint();T;T--) {
    54         std::pair<int64,int64> ans=calc(getint());
    55         printf("%lld %lld
    ",ans.first,ans.second);
    56     }
    57     return 0;
    58 }
  • 相关阅读:
    HWOJ之纠结的优化
    java中的对象数组
    短路特性的运用
    归并排序
    两个有序数列的合并
    java中的注释规范
    堆排序
    堆的建立
    希尔排序
    直接插入排序
  • 原文地址:https://www.cnblogs.com/skylee03/p/8473898.html
Copyright © 2020-2023  润新知