杜教筛 && bzoj3944 Sum

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

 

正解:线性筛+杜教筛。

杜教筛板子题。然而感觉自己还不是很理解的样子。。

唐老师博客:http://blog.csdn.net/skywalkert/article/details/50500009

xLightGod博客:http://blog.xlightgod.com/dirichlet%E5%8D%B7%E7%A7%AF%E4%B8%8E%E6%9D%9C%E6%95%99%E7%AD%9B/

 

杜教筛可以在低于线性复杂度的时间内求出一些积性函数的前缀和。

为了更快地求$F(i)=\sum_{i=1}^{n}f(i)$,我们构造一个函数$g(n)$,求出$(f*g)(n)$的前缀和。

$\sum_{i=1}^{n}(f*g)(i)=\sum_{i=1}^{n}\sum_{d|i}f(d)g(\frac{i}{d})=\sum_{ij<=n}f(i)g(j)=\sum_{i=1}^{n}g(i)F(\left \lfloor \frac{n}{i} \right \rfloor)$

所以$g(1)F(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)F(\left \lfloor \frac{n}{i} \right \rfloor)$

于是我们的目标就是快速求出$\sum_{i=1}^{n}(f*g)(i)$和$g(i)$的前缀和。这样我们的复杂度就是$O(n^{\frac{3}{4}})$,如果我们将$O(n^{\frac{2}{3}})$以内的$F(i)$预处理,那么复杂度就可以降到$O(n^{\frac{2}{3}})$(复杂度怎么证。。)

$g$一般取恒等函数$I$。

 

所以求$\sum_{i=1}^{n}\mu(i)$,那就是求$\sum_{i=1}^{n}\sum_{d|i}\mu(d)-\sum_{i=2}^{n}F(\left \lfloor \frac{n}{i} \right \rfloor)$

则$Ans=1-\sum_{i=2}^{n}F(\left \lfloor \frac{n}{i} \right \rfloor)$

求$\sum_{i=1}^{n}\phi(i)$,那就是求$\sum_{i=1}^{n}\sum_{d|i}\phi(d)-\sum_{i=2}^{n}F(\left \lfloor \frac{n}{i} \right \rfloor)$

则$Ans=\frac{n(n+1)}{2}-\sum_{i=2}^{n}F(\left \lfloor \frac{n}{i} \right \rfloor)$

于是$Ans$的后面那一坨我们用记忆化搜索,空间开不了??我是用的map。开始先把2500000以内的答案线性筛预处理出来,然后搜索即可。(为什么是2500000,因为我发现这样快一些。。复杂度太玄学了。。)

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <complex>
 5 #include <cstring>
 6 #include <cstdlib>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <cmath>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <set>
14 #define inf (1<<30)
15 #define N (2500010)
16 #define il inline
17 #define RG register
18 #define ll long long
19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
20 
21 using namespace std;
22 
23 struct node{ ll phi,mu; }ans;
24 
25 map <ll,ll> Phi,Mu;
26 ll vis[N],phi[N],mu[N],prime[N],n,cnt;
27 
28 il ll gi(){
29     RG ll x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
30     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
31 }
32 
33 il void sieve(){
34     vis[1]=phi[1]=mu[1]=1;
35     for (RG ll i=2;i<N;++i){
36     if (!vis[i]) phi[i]=i-1,mu[i]=-1,prime[++cnt]=i;
37     for (RG ll j=1,k=i*prime[j];j<=cnt && k<N;++j,k=i*prime[j]){
38         vis[k]=1;
39         if (i%prime[j]) phi[k]=phi[i]*phi[prime[j]],mu[k]=-mu[i];
40         else{ phi[k]=phi[i]*prime[j]; break; }
41     }
42     }
43     for (RG ll i=2;i<N;++i) phi[i]+=phi[i-1],mu[i]+=mu[i-1]; return;
44 }
45 
46 il node du(RG ll n){
47     if (n<N) return (node){phi[n],mu[n]};
48     if (Phi[n]) return (node){Phi[n],Mu[n]};
49     RG ll ans1=n*(n+1)>>1,ans2=1,pos=0; RG node res;
50     for (RG ll i=2;i<=n;i=pos+1){
51     pos=n/(n/i),res=du(n/i);
52     ans1-=(pos-i+1)*res.phi;
53     ans2-=(pos-i+1)*res.mu;
54     }
55     Phi[n]=ans1,Mu[n]=ans2;
56     return (node){ans1,ans2};
57 }
58 
59 il void work(){
60     n=gi(); ans=du(n);
61     printf("%lld %lld\n",ans.phi,ans.mu);
62     return;
63 }
64 
65 int main(){
66     File("du");
67     sieve(); RG ll T=gi();
68     while (T--) work();
69     return 0;
70 }

 

posted @ 2017-03-16 16:49  wfj_2048  阅读(895)  评论(0编辑  收藏  举报