同载于 洛谷。
SemiPerfectPower
问区间 \([l,r]\) 中能表示成形如 \(n=ab^c \land a < b \land c>1\) 的数的数量。
\(l \le r \le 5 \cdot 10^6\)。
模拟赛把这个放 T1 家里得请哈基高了。
不容易发现 \(c=2,3\) 的数是完全的。
当 \(c>3\) 时,若 \(c\) 为偶数 \(a(b^{\frac c 2})^2\) 也是合法方案,若为奇数则 \((ab)(b^{\frac {c-1} 2})^2\)。
记 \(P_k(n)=[n\ 没有\ k\ 次因子]\)。
钦定 \(ab^c\) 中 \(P_c(a)=1\) 以确定唯一表示。
单独 \(c=2\) 是好求的,枚举 \(a\) 得到 \(\sum_{a=1}^{n^{\frac 1 3}} P_2(a)(\sqrt{\frac n a}-a)\),式子里的 \(P_k\) 可预处理。
容斥求答案,考虑两种形式都满足的数。
\(ab^3=(ab)b^2=(\frac {ab} {k^2})(bk)^2\),其中 \(k^2\) 为 \(ab\) 最大平方因子,或者说 \(k^2 | ab \land P_2(\frac {ab} {k^2})\)。
这说明统计 \(c=3\) 时要保证 \(\frac {ab} {k^2} \ge bk \rightarrow k^3 \le a\)。
现在要算:
考虑把后面那坨化成两个变量的关系。
把 \(a,k^2\) 的公因子先提了,\(g=\gcd(a,k^2)\ ,\ k'=\frac {k^2} g\ ,\ a'=\frac a g\)。
常规地,令 \(b=k't\),枚举 \(t\)。
最后一个求和变成:
显然 \(P_k\) 是积性函数。
很好,可以莫反。
枚举 \(k,d\) 复杂度是 1/3 power 和 ln 级别的,最后一个求和预处理。总时间复杂度是 \(O(n^{\frac 1 3}\ln {n^{\frac 1 3}})\)。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const int N=1e6+5;
int mu[N],p2[N],p3[N]; vector<ll>d[N],c[N];
inline ll P(ll x,int y){ return x*x*(y&1?x:1)*(y&4?x*x:1); }
ll npow(ll x,int k){ll r=pow(x,1./k)+10,l=r-20,mid;while(l<r) mid=l+r+1>>1,P(mid,k)<=x?l=mid:r=mid-1;return l;
}
void init(ll n){ll n3=npow(n,3)+1,n4=npow(n,4)+1;mu[1]=1;for(ll i=1;i<=n3;i++){for(ll j=i<<1;j<=n3;j+=i)mu[j]-=mu[i];c[i].resize(n3/i+1);p2[i]=!!mu[i],p3[i]=1;}for(ll i=2;i*i*i<=n4;i++)for(ll t=i*i*i,j=t;j<=n4;j+=t) p3[j]=0;for(ll i=1;i<=n3;i++){for(ll j=i;j<=n3;j+=i)d[j].push_back(i);if(p2[i]) for(ll j:d[i]) c[j][i/j]=1;}for(ll i=1;i<=n4;i++){ll lst=0; for(ll &j:c[i]) j+=lst,lst=j;}
}
ll solve(ll n){ll ans=0,n3=npow(n,3),n4=npow(n,4);for(ll a=1;a<=n3;a++) if(p2[a]) ans+=npow(n/a,2)-a;for(ll a=1;a<=n4;a++) if(p3[a])for(ll k=1;k*k*k<=a;k++){ll g=__gcd(a,k*k),_a=a/g,_k=k*k/g;if(!p2[_a]) continue; ll l=a/_k,r=npow(n/a,3)/_k;for(ll D:d[_a]) ans+=mu[D]*(c[D][r/D]-c[D][l/D]);}return ans;
}
int main(){freopen("power.in","r",stdin);freopen("power.out","w",stdout);init(8e16);int T; scanf("%d",&T);while(T--){ll l,r; scanf("%lld%lld",&l,&r);printf("%lld\n",solve(r)-solve(l-1));} return 0;
}