1. 程式人生 > >Codeforces 955C Sad powers(數論)

Codeforces 955C Sad powers(數論)

Codeforces 955C Sad powers

題意

q組詢問,每次詢問給定L,R,求[L,R]區間內有多少個數可以寫成ap的形式,其中a>0,p>1,1 ≤ L ≤ R ≤ 1e18。

思路

  • 對於p>2的情況,由於隨著指數p的增大,小於1e18的p次冪的數量會急劇減小,總數量的級別在1e6多左右,因此可預處理。L,R不超過1e18,可以直接列舉數字1-1e6,將每個數字不超過1e18的且不是平方數的p次冪推入陣列中,排序去重。以便回答詢問時可二分求數量。
  • 對於p=2的情況,對上界直接開方,即可知道有多少個平方數。

做法不難,但容易看不清複雜度,以至於想不到做法。建議手寫開方,否則誤差較大。

程式碼

#include<bits/stdc++.h>
#define dd(x) cout<<#x<<" = "<<x<<" "
#define de(x) cout<<#x<<" = "<<x<<"\n"
#define sz(x) int(x.size())
#define All(x) x.begin(),x.end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> P;
typedef priority_queue<int> BQ;
typedef priority_queue<int,vector<int>,greater<int> > SQ;
const int maxn=1e5+10,mod=1e9+7,INF=0x3f3f3f3f;
ll Sqrt(ll x)
{
    ll l=1,r=x,ans=0;
    while (l<=r)
    {
        ll mid=(l+r)>>1;
        ld mul=ld(mid)*mid;
        if (mul<x)
            l=mid+1,ans=mid;
        else if (mul>x)
            r=mid-1;
        else
            return mid;
    }
    return ans;
}
vector<ll> v;
vector<ll>:: iterator End;
void init()
{
    for (ll i=2;i<=1e6;++i)
    {
        ll a=i*i*i;
        ld _a=a;
        while (_a<=1e18)
        {
            ll t=Sqrt(a);
            if (t*t!=a)
                v.pb(a);
            a*=i;
            _a*=i;
        }
    }
    sort(All(v));
    End=unique(All(v));
}
ll count(ll n)
{
    ll p=upper_bound(v.begin(),End,n)-v.begin();
    return Sqrt(n)+p;
}
int main()
{
    init();
    int n;
    cin>>n;
    while (n--)
    {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",count(r)-count(l-1));
    }
    return 0;
}