[CF665F]Four Divisors
题目大意:
给定$n(n\leq10^{11})$,求$\displaystyle\sum_{i=1}^n[\tau(i)=4]$。
思路:
设$p,q$为不相等的质数,则满足$\tau(i)=4$的数$i$一定可以表示成$pq$或$p^3$。
对于$i=pq$的情况,可以先线性筛预处理出$\sqrt n$以内的质数,然后用LOJ6235的方法,用洲阁筛求出DP数组$f$。加上$last[j]-1$就是当$p_i^2>j$时不用$-1$转移,也就是加上了$p_i^2>j$的质数个数。此时$f[cnt+1-p_i]$表示的就是$\pi(n/p_i)-\pi(\sqrt n)$。统计答案时,枚举素数$p_i$,求$\sum_{p_i\leq\sqrt n}(\pi(n/p_i)-\pi(p_i))$即可。
对于$i=p^3$的情况,直接在筛出来的质数中二分答案即可。
时间复杂度$O\left(\frac{n^{\frac34}}{\ln n}\right)$。
细节:
$n=1$时二分会挂掉,需要特判。
1 #include<cmath> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 #include<functional> 6 typedef long long int64; 7 inline int64 getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int64 x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 const int LIM=316228,P=27294; 15 bool vis[LIM]; 16 int lim,p[P],sum[LIM],last[LIM*2],cnt; 17 int64 n,val[LIM*2],f[LIM*2]; 18 inline void sieve() { 19 for(register int i=2;i<=lim;i++) { 20 if(!vis[i]) p[++p[0]]=i; 21 sum[i]=sum[i-1]+!vis[i]; 22 for(register int j=1;j<=p[0]&&i*p[j]<=lim;j++) { 23 vis[i*p[j]]=true; 24 if(i%p[j]==0) break; 25 } 26 } 27 } 28 int main() { 29 lim=sqrt(n=getint()); 30 sieve(); 31 for(register int64 i=1;i<=n;i=n/(n/i)+1) { 32 val[++cnt]=n/i; 33 } 34 std::reverse(&val[1],&val[cnt]+1); 35 std::copy(&val[1],&val[cnt+1],&f[1]); 36 for(register int i=1;i<=p[0];i++) { 37 for(register int j=cnt;j;j--) { 38 const int64 k=val[j]/p[i],pos=k<=lim?k:cnt+1-n/k; 39 if(k<p[i]) break; 40 f[j]-=f[pos]+last[pos]-i+1; 41 last[j]=i; 42 } 43 } 44 int64 ans=0; 45 for(register int i=1;i<=cnt;i++) { 46 f[i]+=last[i]-1; 47 } 48 for(register int i=1;i<=p[0];i++) { 49 ans+=f[cnt+1-p[i]]-i; 50 } 51 if(n!=1) ans+=std::upper_bound(&p[1],&p[p[0]]+1,floor(pow(n,1./3)))-&p[1]; 52 printf("%lld\n",ans); 53 return 0; 54 }