C. Sad powers
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
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
Copy
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的p次幂所表示的数
思路:
虽然暴力是个好东西,但wa题也是很容易。
最初的想法是:遍历每个数字的每次幂,但很明显是行不通的。有趣的是,走不通的路,也还要试一下看看能过几个样例。然后wa在了第三个样例上。。。有兴趣可以看一眼真·暴力代码。如下:
#include<stdio.h>
#include<string.h>
int vis[]; typedef long long ll; ll push_pow(ll a,ll b)
{
ll ans=;ll base=a;
while(b)
{
if(b%) ans*=base;
base*=base;
b/=;
}
return ans;
} ll slove(ll l,ll r)
{
memset(vis,,sizeof(vis));
int flag=;ll ans1=,ans2=;
for(int i=;flag;i++)
{
for(int j=;;j++)
{
if(l>=push_pow(i,j)&&!vis[push_pow(i,j)])
{
ans1++;
}
if(r>=push_pow(i,j)&&!vis[push_pow(i,j)])
{
vis[push_pow(i,j)]=;ans2++;
}
else if(j==&&!vis[push_pow(i,j)])
{
flag=;
break;
}
else break;
}
}
return ans2-ans1;
} int main()
{
ll T,l,r;
scanf("%lld",&T);
for(int o=;o<=T;o++)
{
scanf("%lld%lld",&l,&r);
if(l==) printf("%lld\n",+slove(l-,r));
else printf("%lld\n",slove(l-,r));
}
return ;
}
真·暴力
暴力不是ac的秘诀,那么这道题该怎么解决呢?在思考无果的情况下,百度。。。
事实它告诉我,这题不是我原先可以解决的。于是乎,涨知识了。
言归正传,我们可以把问题分割,分成两部分,一部分是二次方,一部分是p次方(p>2)。
二次方不必说,二分查找很容易解决问题。
主要是p次方,当p=3时,1e18开三次根号1e6,复杂度在可接受范围内。
而当p>3时,由于幂函数的增幅极大,所以到大于1e18花费的时间是很少的,以最多次幂的2举例,1e18没有爆longlong,那么次数少于64,很明显,花费也是可以接受的。
AC代码如下:
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std; typedef long long ll;
vector<ll>q; int root(ll x) //找根
{
ll left=;ll right=1e9; //left必须从0开始,因为调用函数时会有x==0的情况
ll mid,ans;
while(left<=right)
{
mid=(left+right)>>;
if(mid*mid<=x)
{
ans=mid;
left=mid+;
}
else
{
right=mid-;
}
}
return ans;
} void init() //p>2时,可以由x的p次方表示的数
{
q.clear();
for(ll i=;i<=1e6;i++)
{
double t=1.0*i*i*i;
ll s=i*i*i;
while(t<2e18)
{
ll root_s=root(s);
if(root_s*root_s<s)
q.push_back(s);
t*=i;s*=i;
}
}
sort(q.begin(),q.end()); //下面会解释
unique(q.begin(),q.end());
} int main()
{
init();
ll T;
ll l,r;
scanf("%lld",&T);
for(int i=;i<=T;i++)
{
scanf("%lld%lld",&l,&r);
ll ans1=upper_bound(q.begin(),q.end(),r)-lower_bound(q.begin(),q.end(),l);//下面会解释
ll ans2=root(r)-root(l-);
printf("%lld\n",ans1+ans2);
}
return ;
}
unique()函数
sort(q.begin(),q.end());
unique(q.begin(),q.end());
独一无二的,该函数的作用是把相邻的两个相同的数字中消去一个,让我想起了天梯赛的1-8(AI牛批!
相邻的两个相同的数字,那么sort()函数的作用就体现在为unique()函数服务上了。
upper_bound()与lower_bound()函数
ll ans1=upper_bound(q.begin(),q.end(),r)-lower_bound(q.begin(),q.end(),l);
upper_bound()作用是返回[l,r)中第一个大于某个数字的元素地址,lower_bound()的作用是返回[l,r)中第一个大于等于某个数字的元素地址。