[bzoj3944] sum [杜教筛模板]

题面:

传送门

就是让你求$ \varphi\left(i\right) $以及$ \mu\left(i\right) $的前缀和

思路:

就是杜教筛的模板

我们把套路公式拿出来:

$ g\left(1\right)S\left(n\right)=\sum_{i=1}^{n}\left(g\ast f\right)\left(i\right)-\sum_{i=2}^{n}g\left(i\right)S\left(\frac ni\right) $

其中函数$f$分别为$\varphi$以及$\mu$

对于这两个函数有两个非常好用的卷积公式:

$\left(\mu\ast I\right)=\varepsilon$

$\left(\varphi\ast I\right)=id$

那么我们设g(x)=1,然后把g(x)带进去,两个前缀和就变成了这样的:

$S\left(n\right)=1-\sum_{i=2}^{n}S\left(\frac ni\right)$这个是$\mu$

$S\left(n\right)=\frac{n\ast\left(n+1\right)}{2}-\sum_{i=2}^{n}S\left(\frac ni\right)$这个是$\varphi$

然后递归,记忆化求和就可以了

 

注意最好写成一个递归处理两个答案......不然会T成狗

 

Code:

这里提供两个函数分开的版本,方便查看

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<map>
 6 #define ll long long
 7 using namespace std;
 8 inline ll read(){
 9     ll re=0,flag=1;char ch=getchar();
10     while(ch>'9'||ch<'0'){
11         if(ch=='-') flag=-1;
12         ch=getchar();
13     }
14     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
15     return re*flag;
16 }
17 ll phi[2000010],pri[2000010],tot=0,mu[2000010],n;bool vis[2000010];
18 void init(){
19     ll i,j,k;phi[1]=mu[1]=1;phi[0]=0;
20     for(i=2;i<=2000000;i++){
21         if(!vis[i]){
22             pri[++tot]=i;phi[i]=i-1;mu[i]=-1;
23         }
24         for(j=1;j<=tot;j++){
25             k=i*pri[j];if(k>2000000) break;
26             vis[k]=1;
27             if(i%pri[j]==0){
28                 phi[k]=phi[i]*pri[j];
29                 mu[k]=0;
30                 break;
31             }
32             phi[k]=phi[i]*phi[pri[j]];
33             mu[k]=-mu[i];
34         }
35     }
36     for(i=2;i<=2000000;i++) phi[i]=phi[i-1]+phi[i],mu[i]=mu[i-1]+mu[i];
37 }
38 ll sum1(ll x){return x*(x+1)/2;}
39 ll v1[1000010],v2[1000010],m1[1000010],m2[1000010];
40 ll S1(ll x){
41     if(x<=2000000) return phi[x];
42     ll re=sum1(x);ll i,j,t=n/x;
43     if(v1[t]) return m1[t];
44     for(i=2;i<=x;i=j+1){
45         j=x/(x/i);
46         re-=(j-i+1)*S1(x/i);
47     }
48     v1[t]=1;
49     return m1[t]=re;
50 }
51 ll S2(ll x){
52     if(x<=2000000) return mu[x];
53     ll re=1,i,j,t=n/x;
54     if(v2[t]) return m2[t];
55     for(i=2;i<=x;i=j+1){
56         j=x/(x/i);
57         re-=(j-i+1)*S2(x/i);
58     }
59     v2[t]=1;
60     return m2[t]=re;
61 }
62 int main(){
63     ll T=read();init();
64     while(T--){
65         n=read();memset(v1,0,sizeof(v1));memset(v2,0,sizeof(v2));
66         printf("%lld %lld\n",S1(n),S2(n));
67     }
68 }

 

posted @ 2018-03-08 16:37  dedicatus545  阅读(193)  评论(0编辑  收藏  举报