题目大意
已知 X∈[1,a],Y∈[1,b] X ∈ [ 1 , a ] , Y ∈ [ 1 , b ] ,求不同的 XY X Y 的个数。
解题思路
显然要知道“本质不同”的数有多少个。
“本质的数”x指,
x=Πpkii
x
=
Π
p
i
k
i
,
gcd(ki)=1
g
c
d
(
k
i
)
=
1
这很容易找啊,根号a的时间复杂度就搞定了。
设
m=min(⌊logbx⌋,B)
m
=
m
i
n
(
⌊
l
o
g
b
x
⌋
,
B
)
则要求
i∈[1,m],j∈[1,B]
i
∈
[
1
,
m
]
,
j
∈
[
1
,
B
]
,不同的ij的个数。
这个只枚举ij是很难做的。关注一点,m不会超过29。
关注数1~mB。
将数分为m列,第i列是
[i∗n−n+1,i∗n]
[
i
∗
n
−
n
+
1
,
i
∗
n
]
。
则第i行的数如果能够合法,那么这个数会被
[i,m]
[
i
,
m
]
中任意一个数整除。
容斥?29似乎有点大吧。
关注一个细节。
如果
∃j∈[i,m],j′∈[i,j)
∃
j
∈
[
i
,
m
]
,
j
′
∈
[
i
,
j
)
,且
j′|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;
}