[联合集训6-15] 盟誓的文艺复兴 数论

c = 2 k a b c = a ( b k ) 2 ;若 c = 2 k + 1 , a b c = ( a b ) ( b k ) 2 。所以我们只需要考虑 c 3 的情况。
那么能表示成 a b 2 的很好求,就是 a = 1 n 1 3 μ 2 ( a ) ( n a a ) 。现在考虑求只能被表示成 a b 3 的数的个数。
我们设 k 是满足 k 2 | a b 的最大值,那么 a b 3 = ( a b ) b 2 = a b k 2 ( b k ) 2 ,也就是要满足 a b k 2 b k a k 3 。设 c ( x ) x 有三次因子时为 0 ,否则为 1 ,那么式子就是:

a 4 n c ( a ) k 3 a b = a + 1 ( n a ) 1 3 [ k 2 | a b ] μ 2 ( a b k 2 )

为了处理那个整除,设 g = gcd ( a , k 2 ) , a = a g , k = k 2 g , b = b k ,式子化成:
a 4 n c ( a ) k 3 a b = a k + 1 ( n a ) 1 3 k μ 2 ( a b )

因为 μ ( a b ) = μ ( a ) μ ( b ) [ gcd ( a , b ) = 1 ] ,就有:
a 4 n c ( a ) k 3 a μ 2 ( a ) b = a k + 1 ( n a ) 1 3 k μ 2 ( b ) [ gcd ( a , b ) = 1 ]

其中 [ gcd ( a , b ) = 1 ] 用莫比乌斯反演弄掉就是:
a 4 n c ( a ) k 3 a μ 2 ( a ) d | a μ ( d ) b = a k + 1 ( n a ) 1 3 k [ d | b ] μ 2 ( b )

那么可以发现 d n 1 4 ,对于每个 d 预处理其在 n 1 3 内(因为 b n 1 3 )所有倍数 t μ 2 ( t ) 的前缀和,这样复杂度大概是 O ( n 1 4 log n ) 的。那么我们直接枚举 a , k , d ,因为 μ 2 ( a ) = 0 ,所以复杂度是 O ( n 1 4 n 1 12 2 ω ( n 1 4 ) ) ,其中 ω 表示质因子个数,但其实并没有这么满,是可以过的。
注意直接调用pow函数可能存在精度问题,调用之后左右再判一下即可。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define PB push_back
#define N4 17000
#define N3 440000
#define ll long long
using namespace std;
vector<int> w[N4+5];
int minp[N3+5],pri[N3+5],mu[N3+5],r[10],num;
bool c[N3+5],d[N3+5];
void getpri(int n)
{
    for(int i=1;i<=n;i++)
        minp[i]=i;
    mu[1]=1;    
    for(int i=2;i<=n;i++)
    {
        if(minp[i]==i){mu[i]=-1;pri[++num]=i;}
        for(int j=1;j<=num&&i*pri[j]<=n;j++)
        {           
            minp[i*pri[j]]=pri[j];
            if(i%pri[j]==0) {mu[i*pri[j]]=0;break;}
            mu[i*pri[j]]=-mu[i];
        }
    }
}

void init()
{
    memset(c,1,sizeof(d));
    for(int i=1;i<=N3;i++)
        for(int t=i,p=0,k=0;t>1;t=t/minp[t])
        {
            if(minp[t]!=p) p=minp[t],k=0;
            k++;
            c[i]&=(k<3);
        }
    for(int i=1;i<=N4;i++)
    {
        w[i].PB(0);
        for(int j=i;j<=N3;j+=i)
            w[i].PB(mu[j]*mu[j]);
        for(int j=1;j<w[i].size();j++)
            w[i][j]+=w[i][j-1]; 
    }       
}
int gcd(int x,int y)
{
    for(int t;y;t=x,x=y,y=t%y);
    return x;
}
int root(ll n,int x)
{
    int r=pow(n,1.0/x);
    for(;(ll)r*r*(x==3?r:1)<=n;r++);
    for(;(ll)r*r*(x==3?r:1)>n;r--);
    return r;
}
ll solve(ll n)
{
    ll ans=0;
    for(int a=1;(ll)a*a*a<=n;a++)
        if(mu[a]*mu[a])
        {
            int tmp=root(n/a,2)-a;
            if(tmp<=0) break;
            ans+=tmp;
        }
    for(int a=1;(ll)a*a*a*a<=n;a++)
        if(c[a])
            for(int k=1;k*k*k<=a;k++)
            {
                int g=gcd(k*k,a),a1=a/g,k1=k*k/g;
                if(mu[a1]!=0)
                {
                    int top=0;
                    for(int t=a1;t>1;t=t/minp[t]) r[top++]=minp[t];
                    for(int s=0;s<(1<<top);s++)
                    {
                        int e=1;
                        for(int i=0;i<top;i++)
                            if((s>>i)&1) e=e*r[i];
                        int L=a/k1,R=root(n/a,3)/k1;
                        if(mu[e]==0||R/e<=L/e) continue;    
                        ans+=(ll)mu[e]*(w[e][R/e]-w[e][L/e]);
                    }
                }
            }   
    return ans;     
}
int main()
{
    getpri(N3); 
    init(); 
    ll l,r,tmp;
    scanf("%lld%lld",&l,&r);
    printf("%lld",solve(r)-solve(l-1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dofypxy/article/details/80752330
今日推荐