[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)-\sum\limits_{i=2}^{n}g(i)F(\lfloor\frac{n}{i}\rfloor)$$

设要求的是$f$的前缀和,辅助函数分别是$g$和$h$,$F$,$G$,$H$分别是三个函数的前缀和,如果能在$O(1)$的时间内求出$G$和$H$,就能在$O(n^{\frac{3}{4}})$内求出$F$。复杂度$O(\sum\limits_{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{\lfloor\frac{a}{b}\rfloor}{c} \rfloor=\lfloor \frac{a}{bc} \rfloor$),所以对于后面的值可以把$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\n",phi[n],mu[n]);
42             else solve(n),printf("%lld %lld\n",Phi[1],Mu[1]);
43     }
44     return 0;
45 }

 

posted @ 2018-05-15 23:21  HocRiser  阅读(283)  评论(0编辑  收藏  举报