1. 程式人生 > >bzoj 3944 Sum —— 杜教篩

bzoj 3944 Sum —— 杜教篩

spa while 入門題 long ble algorithm cst col ()

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=3944

杜教篩入門題!

看博客:https://www.cnblogs.com/zjp-shadow/p/8491542.html

寫法模仿其他博客的,但很慢啊...

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
int const
maxn=4000005; ll T,m,p[maxn],phi[maxn],mu[maxn],cnt,mx; bool vis[maxn]; map<ll,ll>mp1,mp2; ll rd() { ll ret=0,f=1; char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();} while(ch>=0&&ch<=9)ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar();
return ret*f; } void init() { int n=mx; phi[1]=1; mu[1]=1; for(int i=2;i<=n;i++) { if(!vis[i])phi[i]=i-1,p[++cnt]=i,mu[i]=-1,vis[i]=1; for(int j=1;j<=cnt&&i*p[j]<=n;j++) { vis[i*p[j]]=1; if(i%p[j]==0) { phi[i
*p[j]]=phi[i]*p[j]; mu[i*p[j]]=0; break; } phi[i*p[j]]=phi[i]*(p[j]-1); mu[i*p[j]]=-mu[i]; } } for(int i=1;i<=n;i++)mu[i]+=mu[i-1],phi[i]+=phi[i-1]; } void dfs(ll n,ll &ans1,ll &ans2) { if(n<mx){ans1=phi[n]; ans2=mu[n]; return;} if(mp1.count(n)){ans1=mp1[n]; ans2=mp2[n]; return;} ans1=(n+1)*n/2; ans2=1; for(ll i=2,lst;i<=n;i=lst+1) { lst=n/(n/i);// i ~ n/(n/i) 答案都相同 ll tmp1,tmp2; dfs(n/i,tmp1,tmp2); ans1-=tmp1*(lst-i+1); ans2-=tmp2*(lst-i+1); } mp1[n]=ans1; mp2[n]=ans2; } int main() { mx=4000000; init(); T=rd(); while(T--) { m=rd(); ll ans1,ans2; dfs(m,ans1,ans2); printf("%lld %lld\n",ans1,ans2); } return 0; }

bzoj 3944 Sum —— 杜教篩