您的位置:首页 > 其它

[BZOJ3944]Sum(杜教筛)

2018-05-15 23:21 309 查看

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就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std;

const int N=2000010,M=100010;
int T,n,m,tot,p
;
ll phi
,mu
,Phi[M],Mu[M];
bool vis[M];

ll getphi(int x){ if (x<=m) return phi[x]; else return Phi[n/x]; }
ll getmu(int x){ if (x<=m) return mu[x]; else return Mu[n/x]; }

void solve(int x){
if (x<=m) return;
int t=n/x,lst=1; ll p1=0,p2=0;
if (vis[t]) return;
vis[t]=1; Phi[t]=(1ll*x+1)*x>>1; Mu[t]=1;
while (lst<x){
int i=lst+1; lst=x/(x/i); solve(x/i);
p1+=getphi(x/i)*(lst-i+1); p2+=getmu(x/i)*(lst-i+1);
}
Phi[t]-=p1; Mu[t]-=p2;
}

int main(){
freopen("bzoj3944.in","r",stdin);
freopen("bzoj3944.out","w",stdout);
scanf("%d",&T); m=2000000; phi[1]=mu[1]=1;
rep(i,2,m){
if (!phi[i]) p[++tot]=i,phi[i]=i-1,mu[i]=-1;
for (int j=1; j<=tot && i*p[j]<=m; j++)
if (i%p[j]==0) { phi[i*p[j]]=p[j]*phi[i]; mu[i*p[j]]=0; break; }
else phi[i*p[j]]=(p[j]-1)*phi[i],mu[i*p[j]]=-mu[i];
}
rep(i,2,m) phi[i]=phi[i-1]+phi[i],mu[i]=mu[i-1]+mu[i];
while (T--){
scanf("%d",&n); memset(vis,0,sizeof(vis));
if (n<=m) printf("%lld %lld\n",phi
,mu
);
else solve(n),printf("%lld %lld\n",Phi[1],Mu[1]);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: