Sad powers(CF 955Div2 C 二分+map+思路+数学)

You're given Q queries of the form (L, R).

For each query you have to find the number of such x that L ≤ x ≤ R and there exist integer numbers a > 0, p > 1 such that x = ap.

Input

The first line contains the number of queries Q (1 ≤ Q ≤ 105).

The next Q lines contains two integers L, R each (1 ≤ L ≤ R ≤ 1018).

Output

Output Q lines — the answers to the queries.

Example

Input

6
1 4
9 9
5 7
12 29
137 591
1 1000000

Output

2
1
0
3
17
1111

Note

In query one the suitable numbers are 1 and 4.

题意:

给定一个区间[l,r],问区间内有多少个数x满足x=a^q,并且a>0&&q>1

题解:

问存在多少个x满足x=a^q,如果数据小的话可以直接把a^q出现的数字用map容器存储起来,排个序输出就行了。

不过,这道题的l和r的范围是1e19,没办法对所有范围的数据都暴力存储起来,不过我们可以对部分进行这样的操作

当q=2的时候,a的范围是1e9,单独分析:

毋庸置疑,x^2在x轴上是单调的,那么我们就可以使用二分的方法判断在[l,r]区间范围内有多少个x^2。

右边界:r,左边界:l-1

通过右边界对应的数我们找到一个x,通过左边界对应的数我们找到一个数y,那么x-y就是指数为2的数量。

当q>2的时候,a的范围小于等于1e6,可以暴力:

将所有的情况使用map容器存起来,然后用sort进行一个排序,接下来使用upper_bound函数找到l和r中间有多少个数成立。

 

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long  long ll;

vector<ll>number;
map<ll,int>mapp;

bool sqrtt(ll x)
{
    ll y=sqrt(x);
    if(y*y==x||(y+1)*(y+1)==x||(y-1)*(y-1)==x)
        return true;
    return false;
}

void init()
{
    number.push_back(1);
    for(ll i=2;i<=1e6;++i)
    {
        for(ll j=i*i*i;j<=1e18;j*=i)
        {
            if(!mapp[j]&&!sqrtt(j))
            {
                //去重复的数字和平方数字
                mapp[j]=1;
                number.push_back(j);
            }
            if(1e18/i<j) break;
        }
    }
    sort(number.begin(),number.end());
}

ll value(ll x)
{
    ll l=1,r=1e9;
    ll mid,ans=0;
    while(l<=r)
    {
       mid=(l+r)/2;
        if(mid*mid<=x)
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    return ans;
}

ll solve(ll l,ll r)
{
    return value(r)-value(l-1);
}

int main()
{
    ll T,l,r;
    init();
    cin>>T;
    while(T--)
    {
        scanf("%I64d%I64d",&l,&r);
        ll ans=0;
        ans+=upper_bound(number.begin(),number.end(),r)-upper_bound(number.begin(),number.end(),l-1);
        ans+=solve(l,r);
        if(l==1) ans-=1;
        printf("%I64d\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值