题目大意
已知 ,求不同的 的个数。
解题思路
显然要知道“本质不同”的数有多少个。
“本质的数”x指,
,
这很容易找啊,根号a的时间复杂度就搞定了。
设
则要求
,不同的ij的个数。
这个只枚举ij是很难做的。关注一点,m不会超过29。
关注数1~mB。
将数分为m列,第i列是
。
则第i行的数如果能够合法,那么这个数会被
中任意一个数整除。
容斥?29似乎有点大吧。
关注一个细节。
如果
,且
则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;
}