955C. Sad powers(思維)
題目鏈接:傳送門
思路:對於1到n的滿足的數(冪次>1)。
我們可以將之分爲兩種,一種是,另一種且不是完全平方數的個數。
對於第一種情況(),即我們計算完全平方數的個數,這部我們可以二分
對於第二種情況(),因爲時這樣數最多隻有種,的則更少,所以這種情況的數我們可以暴力預處理。
但是第二種情況可能有重複計算,我們去重即可。但是第一種情況和第二種情況可能也有重複計算,我們再篩去第二種情況的完全平方數。
這樣我們計算即小於等於,滿足的數,計算出第一種情況即可,計算第二種情況的即可。
代碼:
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
vector<ll> _o,o;
ll root(ll x)
{
ll ans=0;
ll l=1,r=1e9;
while(l<=r)
{
ll m=(l+r)/2;
if(m*m<=x){
ans=m;
l=m+1;
}
else r=m-1;
}
return ans;
}
ll f(ll n)
{
int ans=upper_bound(o.begin(),o.end(),n)-o.begin();
return ans+root(n);
}
void init()
{
ll U=1e18;
for(ll i=2;i<=1000000;++i)
{
for(ll cur=i*i*i;cur<=U;cur*=i)
{
_o.push_back(cur);
if(cur> U/i) break;
}
}
sort(_o.begin(),_o.end());
_o.erase(unique(_o.begin(),_o.end()),_o.end());
for(ll &v:_o)
{
ll r=root(v);
if(r*r==v) continue;
o.push_back(v);
}
}
ll solve(ll l,ll r)
{
return f(r)-f(l-1);
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
init();
int t;
cin>>t;
while(t--)
{
ll l,r;
cin>>l>>r;
cout<<solve(l,r)<<endl;
}
}
這裏提供一種容斥,但是超時的思路。
滿足,的數的 無非是,又因爲所有合數(如6=2*3),所以冪次爲合數的數也是冪次爲素數的數。
所以我們我們只需 取即可。但是像冪次爲這樣有重複計算,即冪次爲的,所以這裏就用到容斥了,我們容斥的是冪次爲的數的個數。
對於的我們不予處理,因爲滿足冪次爲的數爲0個,預處理後發現容斥裏面的冪次的個數有個。
但是要怎麼計算1~n內冪次爲次的數的個數呢?
用即可,不過因爲有誤差,所以我們需要檢測前面或後面的是否滿足。
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int num[1005],tot;
int rc[maxn],cnt;
int top;
vector<int> prime;
int book[1005];
bool check(ll a,ll b,ll n)//return a^b<=n
{
ll ans=1;
for(ll i=1; i<b; ++i)
{
n/=a;
}
if(a <= n)return true;
else return false;
}
void init()
{
book[1]=1;
for(int i=2; i<=63; ++i)
{
if(!book[i])
{
prime.push_back(i);
for(int j=i*i; j<=63; j+=i) book[j]=1;
}
}
tot=0;
for(int p:prime)
num[tot++]=p;
cnt=0;
rc[cnt++]=-1;
for(int i=0; i<tot; ++i)
{
int k=cnt;
for(int j=0; j<k; ++j)
{
ll m=num[i]*(rc[j] < 0? -1 *rc[j]:rc[j]);
if(m > 63)
continue;
rc[cnt++]=m*(rc[j]<0?1:-1);
}
}
}
ll getnum(ll n,ll k)//take maximal a of a^k<=n
{
ll r=pow(1.0*n,1.0/k);
while(!check(r,k,n)) --r;
while(check(r+1,k,n)) ++r;
return r-1;
}
ll getcnt(ll n)
{
if(n==0) return 0;
if(n < 4) return 1;
int top=0;
ll m=n;
ll ans=1;
for(int i=1; i<cnt; ++i)
{
if(rc[i] < 0)
ans-=getnum(n,rc[i]*-1);
else
ans+=getnum(n,rc[i]);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
init();
ll l,r,t;
cin>>t;
while(t--)
{
cin>>l>>r;
cout<<getcnt(r)-getcnt(l-1)<<endl;
}
return 0;
}