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在了第三个样例上。。。有兴趣可以看一眼真·暴力代码。如下:
1 #include<stdio.h>
2 #include<string.h>
3 int vis[100000000];
4
5 typedef long long ll;
6
7 ll push_pow(ll a,ll b)
8 {
9 ll ans=1;ll base=a;
10 while(b)
11 {
12 if(b%2) ans*=base;
13 base*=base;
14 b/=2;
15 }
16 return ans;
17 }
18
19 ll slove(ll l,ll r)
20 {
21 memset(vis,0,sizeof(vis));
22 int flag=1;ll ans1=0,ans2=0;
23 for(int i=2;flag;i++)
24 {
25 for(int j=2;;j++)
26 {
27 if(l>=push_pow(i,j)&&!vis[push_pow(i,j)])
28 {
29 ans1++;
30 }
31 if(r>=push_pow(i,j)&&!vis[push_pow(i,j)])
32 {
33 vis[push_pow(i,j)]=1;ans2++;
34 }
35 else if(j==2&&!vis[push_pow(i,j)])
36 {
37 flag=0;
38 break;
39 }
40 else break;
41 }
42 }
43 return ans2-ans1;
44 }
45
46 int main()
47 {
48 ll T,l,r;
49 scanf("%lld",&T);
50 for(int o=1;o<=T;o++)
51 {
52 scanf("%lld%lld",&l,&r);
53 if(l==1) printf("%lld\n",1+slove(l-1,r));
54 else printf("%lld\n",slove(l-1,r));
55 }
56 return 0;
57 }
暴力不是ac的秘诀,那么这道题该怎么解决呢?在思考无果的情况下,百度。。。
事实它告诉我,这题不是我原先可以解决的。于是乎,涨知识了。
言归正传,我们可以把问题分割,分成两部分,一部分是二次方,一部分是p次方(p>2)。
二次方不必说,二分查找很容易解决问题。
主要是p次方,当p=3时,1e18开三次根号1e6,复杂度在可接受范围内。
而当p>3时,由于幂函数的增幅极大,所以到大于1e18花费的时间是很少的,以最多次幂的2举例,1e18没有爆longlong,那么次数少于64,很明显,花费也是可以接受的。
AC代码如下:
1 #include<stdio.h>
2 #include<vector>
3 #include<algorithm>
4 using namespace std;
5
6 typedef long long ll;
7 vector<ll>q;
8
9 int root(ll x) //找根
10 {
11 ll left=0;ll right=1e9; //left必须从0开始,因为调用函数时会有x==0的情况
12 ll mid,ans;
13 while(left<=right)
14 {
15 mid=(left+right)>>1;
16 if(mid*mid<=x)
17 {
18 ans=mid;
19 left=mid+1;
20 }
21 else
22 {
23 right=mid-1;
24 }
25 }
26 return ans;
27 }
28
29 void init() //p>2时,可以由x的p次方表示的数
30 {
31 q.clear();
32 for(ll i=2;i<=1e6;i++)
33 {
34 double t=1.0*i*i*i;
35 ll s=i*i*i;
36 while(t<2e18)
37 {
38 ll root_s=root(s);
39 if(root_s*root_s<s)
40 q.push_back(s);
41 t*=i;s*=i;
42 }
43 }
44 sort(q.begin(),q.end()); //下面会解释
45 unique(q.begin(),q.end());
46 }
47
48 int main()
49 {
50 init();
51 ll T;
52 ll l,r;
53 scanf("%lld",&T);
54 for(int i=1;i<=T;i++)
55 {
56 scanf("%lld%lld",&l,&r);
57 ll ans1=upper_bound(q.begin(),q.end(),r)-lower_bound(q.begin(),q.end(),l);//下面会解释
58 ll ans2=root(r)-root(l-1);
59 printf("%lld\n",ans1+ans2);
60 }
61 return 0;
62 }
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)中第一个大于等于某个数字的元素地址。
来源:oschina
链接:https://my.oschina.net/u/4358626/blog/3585319