• CodeForce-955C


    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
    ",1+slove(l-1,r));
    54         else printf("%lld
    ",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
    ",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)中第一个大于等于某个数字的元素地址。

  • 相关阅读:
    国外名校课程视频爆红 网友总结“必杀技”(图)
    设置mysql密码
    Writing Linux LCD drivers—深入分析framebuffer设备驱动的结构
    LAMP架构中,php 与 php、php与C语言程序等 之间 的网络通信 问题
    API & ABI
    Linux 6初体验:桌面性能堪比新版Ubuntu
    diff 比较两个文件夹
    11种错误的保养皮肤习惯
    服务器领域Linux击败Windows的5大理由
    CentOS5.5 FTP安装配置
  • 原文地址:https://www.cnblogs.com/noback-go/p/10659327.html
Copyright © 2020-2023  润新知