题解 SP20174 【DIVCNT3 - Counting Divisors (cube)】
首先这题是一道洲阁筛板子题,就当做是一篇洲阁筛讲解吧不要跟我提啥min25,另外部分内容参考自__debug大神的博客在此%%%OrzstO%%%一下。
洲阁筛和杜教筛一样,是用来在低于
好了,这个题让我们求这个:
然后我们不妨以
然后剩下的数既大于
对于①式因为
首先这个区间内的质数它必须是大于
于是就可以有这样一个递推的思路(我发现这种把问题递推出来的思路我自己肯定想不出来……),就是设
注意
然后我们来考虑他的优化。先明确一下我们的目标是对每个
然而这样做复杂度仍然是暴力,但是我们可以接着用一开头就用过的根号思想,就是在
然后递推出这个
然后我们就成功地解决了①式。这个②式我们可以采用和上面一样的递推的做法,显然我们可以把这个式子前缀和相减一下,那么就是求一段区间内
然后这个式子应该也可以用和
然后这题就做完了……
然后你在理论上分析完这题可做,然后一写代码发现越写越恶心……因为全都是一堆细节问题……建议在写代码之前在一张纸上把整个过程一点不漏的写出来。然后下面是一些实现上的问题。
1.我们对每次询问需要的
2.我们要把
3.在求一段区间内的质数有多少个小于
4.
另外不要高估了这题的数据……虽然有
上代码~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define int unsigned long long
#define p 19260817
using namespace std;
typedef unsigned long long ll;
namespace ywy{
typedef struct _n{
ll data;int dp;int nxt;
}
node;node memchi[2000001];
int gn=1;int heads[19260818];
inline void insert(ll data,int dp){
memchi[gn].data=data;
memchi[gn].dp=dp;
memchi[gn].nxt=heads[data%p];
heads[data%p]=gn;gn++;
}
inline int get(ll data){
for(register int i=heads[data%p];i;i=memchi[i].nxt){
if(memchi[i].data==data)return(memchi[i].dp);
}return(0);
}
inline ll get(){
ll n=0;char c;while((c=getchar())||23333){
if(c>='0'&&c<='9')break;if(c=='-')goto s;
}n=c-'0';while((c=getchar())||23333){
if(c>='0'&&c<='9')n=n*10+c-'0';else return(n);
}s:while((c=getchar())||23333){
if(c>='0'&&c<='9')n=n*10-c+'0';else return(n);
}return(0);
}
int nearby[400001];
void iprint(ll num){
if(num>=10)iprint(num/10);
putchar(num%10+'0');
}
int prime[400001];
unsigned char bv[400001];
int ptr=1;
int mindiv[400001];
ll sig[400001],sums[400001];
inline void prim(int n){
for(register int i=2;i<=n;i++){
if(!bv[i]){
nearby[i]=ptr;
prime[ptr]=i;ptr++;
mindiv[i]=i;
}for(register int j=1;j<ptr;j++){
int cjr=i*prime[j];
if(cjr>n)break;
mindiv[cjr]=prime[j];
bv[cjr]=1;
if(i%prime[j]==0)break;
}
}for(register int i=1;i<=n;i++){
if(!nearby[i])nearby[i]=nearby[i-1];
ll ans=1;int tmp=i;
while(tmp!=1){
int d=mindiv[tmp];int k=1;
while(mindiv[tmp]==d)k+=3,tmp/=d;ans*=k;
}
sig[i]=ans;
sums[i]=sums[i-1]+ans;
}
}
ll f[2][4000001],g[2][4000001];
inline int erfen(ll n){
int ans=0,l=1,r=ptr-1;
while(l<=r){
int mid=(l+r)>>1;
if((ll)prime[mid]*(ll)prime[mid]<=n)ans=mid,l=mid+1;
else r=mid-1;
}return(ans);
}
ll ints[4000001];
ll n;ll sqr;int sqrp;int pos=0;
int i0[1000001];ll rg[1000001];
inline int how(int l,int r,ll x){
if(l>r)return(0);
if(prime[r]<=x)return(r-l+1);
if(prime[l]>x)return(0);
return(nearby[x]-l+1);
}
inline void getg(){
for(register int i=0;i<pos;i++)g[0][i]=ints[i],i0[i]=0,rg[i]=0;
for(register int i=1;i<=sqrp;i++){
for(register int j=pos-1;~j&&!i0[j];j--){
ll ans=g[(i-1)&1][j];
if(prime[i]>ints[j]/prime[i]){
i0[j]=i;ans-=(ints[j]>=prime[i]);rg[j]=ans;
}else{
int dst=get(ints[j]/prime[i]);
if(i0[dst])ans-=(rg[dst]-how(i0[dst]+1,i-1,ints[j]/prime[i]));
else ans-=g[(i-1)&1][dst];
}g[i&1][j]=ans;
}
}
}
int fi0[4000001];
inline void getf(){
for(register int i=0;i<pos;i++)fi0[i]=0,f[0][i]=f[1][i]=0;
for(register int i=1;i<=sqrp;i++){
for(register int j=pos-1;~j&&prime[sqrp-i+1]<=ints[j]/prime[sqrp-i+1];j--){
ll ans=f[(i-1)&1][j];
if(!fi0[j])fi0[j]=i,ans=1ll+4ll*(ll)how(sqrp-i+2,sqrp,ints[j]);
ll ji=prime[sqrp-i+1],F=4;
while(ji<=ints[j]){
int dst=get(ints[j]/ji);
if(!fi0[dst]){
ans+=F*(1ll+4ll*(ll)how(sqrp-i+2,sqrp,ints[j]/ji));
}
else{
ans+=F*f[(i-1)&1][dst];
}
ji*=prime[sqrp-i+1];F+=3;
}
f[i&1][j]=ans;
}
}
}
void ywymain(){
prim(400000);int t=get();
while(t){
t--;n=get();
if(n<=400000){
iprint(sums[n]);putchar('\n');continue;
}
sqr=sqrt(n),sqrp=erfen(n);pos=0;
for(register ll i=1;i<=n;){
ints[pos]=n/i;pos++;i=n/(n/i)+1;
}
for(register int i=1;i<=sqr;){
ints[pos]=sqr/i;pos++;i=sqr/(sqr/i)+1;
}
sort(ints,ints+pos);
pos=unique(ints,ints+pos)-ints;
for(register int i=0;i<pos;i++){
insert(ints[i],i);
}
getg();getf();
ll a=f[sqrp&1][get(n)],b=f[sqrp&1][get(sqr)];
if(!fi0[get(n)])a=1ll+4ll*how(1,sqrp,n);
if(!fi0[get(sqr)])b=1ll+4ll*how(1,sqrp,sqr);
ll ans=a-b;
for(register int i=1;i<=sqr;i++){
int ywy=get(n/i);
ll cjr=g[sqrp&1][ywy];
if(i0[ywy])cjr=rg[ywy]-how(i0[ywy]+1,sqrp,n/i);
ans+=((cjr-1ll)*4ll+1ll)*sig[i];
}
iprint(ans);putchar('\n');
for(register int i=0;i<pos;i++){
heads[ints[i]%p]=0;
}gn=1;
}
}
}
signed main(){
ywy::ywymain();return(0);
}