zoukankan      html  css  js  c++  java
  • [BZOJ3944]Sum(杜教筛)

    3944: Sum

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 6201  Solved: 1606
    [Submit][Status][Discuss]

    Description

     

    Input

    一共T+1行
    第1行为数据组数T(T<=10)
    第2~T+1行每行一个非负整数N,代表一组询问
     

    Output

    一共T行,每行两个用空格分隔的数ans1,ans2
     

    Sample Input

    6
    1
    2
    8
    13
    30
    2333

    Sample Output

    1 1
    2 0
    22 -2
    58 -3
    278 -3
    1655470 2

    HINT

     

    Source

     
    [Submit][Status][Discuss]

    最基础的杜教筛。

    杜教筛实际上就是这样一个式子:$$F(n)=H(n)-sumlimits_{i=2}^{n}g(i)F(lfloorfrac{n}{i} floor)$$

    设要求的是$f$的前缀和,辅助函数分别是$g$和$h$,$F$,$G$,$H$分别是三个函数的前缀和,如果能在$O(1)$的时间内求出$G$和$H$,就能在$O(n^{frac{3}{4}})$内求出$F$。复杂度$O(sumlimits_{i=1}^{sqrt{n}} sqrt{frac{n}{i}})=O(n^frac{4}{3})$,通过预处理前$n^{frac{2}{3}}$个数就可以做到$O(n^{frac{2}{3}})$了。

    对于后面的$F(n)$值数组下标不可能直接记录,但是注意到我们最终需要的$F$函数值最多有$O(n^{frac{2}{3}})$个(因为$lfloor frac{lfloorfrac{a}{b} floor}{c} floor=lfloor frac{a}{bc} floor$),所以对于后面的值可以把$x$存到$n/x$里。

    回到这题,不要爆int就好了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=2000010,M=100010;
     9 int T,n,m,tot,p[N];
    10 ll phi[N],mu[N],Phi[M],Mu[M];
    11 bool vis[M];
    12 
    13 ll getphi(int x){ if (x<=m) return phi[x]; else return Phi[n/x]; }
    14 ll getmu(int x){ if (x<=m) return mu[x]; else return Mu[n/x]; }
    15 
    16 void solve(int x){
    17     if (x<=m) return;
    18     int t=n/x,lst=1; ll p1=0,p2=0;
    19     if (vis[t]) return;
    20     vis[t]=1; Phi[t]=(1ll*x+1)*x>>1; Mu[t]=1;
    21     while (lst<x){
    22         int i=lst+1; lst=x/(x/i); solve(x/i);
    23         p1+=getphi(x/i)*(lst-i+1); p2+=getmu(x/i)*(lst-i+1);
    24     }
    25     Phi[t]-=p1; Mu[t]-=p2;
    26 }
    27 
    28 int main(){
    29     freopen("bzoj3944.in","r",stdin);
    30     freopen("bzoj3944.out","w",stdout);
    31     scanf("%d",&T); m=2000000; phi[1]=mu[1]=1;
    32     rep(i,2,m){
    33         if (!phi[i]) p[++tot]=i,phi[i]=i-1,mu[i]=-1;
    34         for (int j=1; j<=tot && i*p[j]<=m; j++)
    35             if (i%p[j]==0) { phi[i*p[j]]=p[j]*phi[i]; mu[i*p[j]]=0; break; }
    36                         else phi[i*p[j]]=(p[j]-1)*phi[i],mu[i*p[j]]=-mu[i];
    37     }
    38     rep(i,2,m) phi[i]=phi[i-1]+phi[i],mu[i]=mu[i-1]+mu[i];
    39     while (T--){
    40         scanf("%d",&n); memset(vis,0,sizeof(vis));
    41         if (n<=m) printf("%lld %lld
    ",phi[n],mu[n]);
    42             else solve(n),printf("%lld %lld
    ",Phi[1],Mu[1]);
    43     }
    44     return 0;
    45 }
  • 相关阅读:
    为Android编译bash
    编译toybox
    RGB信仰灯
    如何用Fiddler抓BlueStacks的HTTPS包
    Adobe Acrobat快捷方式
    [MS-SHLLINK]: Shell Link (.LNK) Binary File Format
    BZOJ 3993 星际战争
    BZOJ 3996 线性代数
    BZOJ 1797 最小割
    BZOJ 2726 任务安排
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9043695.html
Copyright © 2011-2022 走看看