JZOJ 4392. 【GDOI2016模拟3.16】幂

题目大意

已知 X [ 1 , a ] , Y [ 1 , b ] ,求不同的 X Y 的个数。

解题思路

显然要知道“本质不同”的数有多少个。
“本质的数”x指, x = Π p i k i g c d ( k i ) = 1
这很容易找啊,根号a的时间复杂度就搞定了。
m = m i n ( l o g b x , B )
则要求 i [ 1 , m ] , j [ 1 , B ] ,不同的ij的个数。
这个只枚举ij是很难做的。关注一点,m不会超过29。
关注数1~mB。
将数分为m列,第i列是 [ i n n + 1 , i n ]
则第i行的数如果能够合法,那么这个数会被 [ i , m ] 中任意一个数整除。
容斥?29似乎有点大吧。
关注一个细节。
如果 j [ i , m ] , j [ i , j ) ,且 j | j
则j可以被筛掉。那么参加容斥的最多也就15个数了。

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 40010
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL A,B;
int i,j,k,S[30];
LL temp,ans,lim,l,r;
LL lmt,cnt[31],c[30];
LL res,ctb,cnt1;
bool bz[N],bb[30];
LL gcd(LL x,LL y){return !y?x:gcd(y,x%y);}
void dg(int x,int fh,LL lcm){
    if(x>c[0]){
        if(lcm==-1)return;
        ctb+=fh*(r/lcm-l/lcm);
        return;
    }
    if(lcm==-1)dg(x+1,-fh,c[x]);
          else dg(x+1,-fh,lcm*c[x]/gcd(lcm,c[x]));
    dg(x+1,fh,lcm);
}
int main(){
    fo(i,1,30)S[i]=sqrt(i);
    scanf("%lld%lld",&A,&B);
    l=sqrt(A);res=A-l;
    ans=1;
    fo(i,2,l)if(!bz[i]){
        temp=i;lim=A/i;
        lmt=1;
        while(1){
            if(temp>lim)break;
            temp*=i;
            if(temp<=l){
                bz[temp]=1;
            }else res--;
            lmt++;
        }
        cnt[lmt]++;
    }
    cnt[1]+=res;
    fo(k,1,30){
        if(k==1)ctb+=B;else{
            ctb=B;
            l=0;r=B;cnt1=1;
            while(r<k*B){
                cnt1++;
                l+=B;r+=B;
                memset(bb,0,sizeof(bb));
                fo(j,cnt1,k)fo(i,cnt1,j-1)if(j%i==0){
                    bb[j]=1;
                    break;
                }
                c[0]=0;
                fo(j,cnt1,k)if(!bb[j])c[++c[0]]=j;
                dg(1,-1,-1);
            }
        }
        ans+=cnt[k]*ctb;
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/huangjingyuan107/article/details/81088351