955C. Sad powers(思維)

955C. Sad powers(思維)

題目鏈接:傳送門

思路:對於1到n的滿足ab=xa^b=x的數xx(冪次bb>1)。

我們可以將之分爲兩種,一種是b=2b=2,另一種b>2b>2且不是完全平方數的個數。

對於第一種情況(b==2b==2),即我們計算完全平方數的個數,這部我們可以二分O(logn)O(logn)

對於第二種情況(b>2b>2),因爲b=3b=3時這樣數最多隻有1018/3=10610^{18/3}=10^6種,b>3b>3的則更少,所以這種情況的數我們可以暴力預處理。

但是第二種情況可能有重複計算,我們去重即可。但是第一種情況和第二種情況可能也有重複計算,我們再篩去第二種情況的完全平方數。

這樣我們計算f(n)f(n)即小於等於nn,滿足ab=xa^b=x的數,O(logn)O(logn)計算出第一種情況即可,O(n)O(log1e6)O(n)-O(log1e6)計算第二種情況的即可。

代碼:

#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;
    }
}

這裏提供一種容斥,但是超時的思路。

滿足ab=xa^b=x,的數的 bb 無非是2,3,...632,3,...63,又因爲所有合數(如6=2*3),所以冪次爲合數的數也是冪次爲素數的數。

所以我們我們只需 bb2,3,5,7,11...2,3,5,7,11...即可。但是像冪次爲2,32,3這樣有重複計算,即冪次爲66的,所以這裏就用到容斥了,我們容斥的是冪次爲2,3,5,7,11,...2,3,5,7,11,...的數的個數。

對於b>63b > 63的我們不予處理,因爲滿足冪次爲>63>63的數爲0個,預處理後發現容斥裏面的冪次的個數有3838個。

但是要怎麼計算1~n內冪次爲bb次的數的個數呢?

pow(n,1/b)pow(n,1/b)即可,不過因爲有誤差,所以我們需要檢測前面或後面的是否滿足abba^b\le b

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章