zoukankan      html  css  js  c++  java
  • 51nod 1105 二分答案法标准题目

    二分答案法例题,用于练习二分答案的基本思想非常合适,包括了思维方式转换的内容(以前我们所做的一直是利用二分法求得数组元素对应指针之类,但是现在是直接对答案进行枚举)。

    思路是:首先对输入数组进行排序,使得a,b两数组都相对有序。

    接下来对每个数字进行二分枚举,之后,通过判断这个数组当前的排名来进行下一步的二分。

    对于每个数字排名的方式通过对枚举每一个a数组中的位置来确定,之后二分对应的数组元素的位置得到,时间复杂度是NLOGN;

    整个算法时间复杂度是NLOGNLOG(N*N)带入50000计算得到的值大概是两千六百万的样子,实际加上cin.sync_with_stdio(false);跑出来的结果大概是300毫秒的样子。。看上去51nod的服务器还是比较快的。事实上,因为输入数据量大,使用输入优化一定程度上有些奇妙的速度优势。但是其实不加这个优化大概时间在500毫秒,其实也是差不多的。

     说实话当时再设计完这个代码的时候超级心虚。。。觉得随便那个常数没搞好就得玩炸了。。。。结果来看危险也许是挺危险,但是也还有一定的容错空间。

    最初的再设计出来统计大于某元素数量的方式之后发现复杂度有点小爆炸。。。以至于对于进一步的爆炸设计有些心虚。。。。

    当时提出的替代方案是首先从A中枚举在一个数字,让他满足A[K]*B[0]<TARGET&&A[K]*B[N-1]>TARGET

    之后进行下一部枚举——找到一个B元素,使得A[k]*B[I]<TARGET&&A[K]*B[I+1]>TARGET

    之后使用B[I]反推A[I]。但是发现只这种方法其实要正确实现复杂度反而比之前的方案复杂度更高,因为在反推这一步没法使用二分法——无法凭空确定是哪个A[k]正好能满足要求,也同时无法确定B[I]先去的正确性。。。。于是,GG。

     http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1105

    下面是代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const long long MAXN=50233;
     4 long long a[MAXN];
     5 long long b[MAXN];
     6 long long n,k;
     7 void init()
     8 {
     9     cin>>n>>k;
    10     for(int i=0;i<n;++i)
    11     {
    12         cin>>a[i]>>b[i];
    13     }
    14     sort(a,a+n);
    15     sort(b,b+n);
    16 }
    17 long long calculate(long long key)
    18 {
    19     long long ret=0;
    20     for(int i=0;i<n;++i)
    21     {
    22         long long tar=key/a[i];
    23         if(tar*a[i]!=key)tar++;
    24         long long pos=lower_bound(b,b+n,tar)-b;
    25         ret+=pos;
    26     }return ret;
    27 }
    28 long long step(long long a,long long b,long long target)
    29 {
    30     if(a==b-1)return a;
    31     long long mid=(a+b)/2;
    32     long long res=calculate(mid);
    33     if(res<=target)return step(mid,b,target);
    34     else return step(a,mid,target);
    35 
    36 }
    37 int main()
    38 {
    39     cin.sync_with_stdio(false);
    40     init();
    41     cout<<step(a[0]*b[0],a[n-1]*b[n-1]+1,n*n-k);
    42     return 0;
    43 }

    代码其实很好写。。。但是因为没带电脑等等原因,这份代码差不多是大的第四遍了。。。。。。

     另外就是发现了一点,加了输入优化反而更慢了,下面是加了输入优化的AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const long long MAXN=50233;
    long long a[MAXN];
    long long b[MAXN];
    long long n,k;
    void read_(long long &ret)
    {
        ret=0;
        char c=0;
        while((c<'0'||c>'9'))c=getchar();
        while(c>='0'&&c<='9')ret*=10,ret+=c-'0',c=getchar();
    }
    void init()
    {
    //    cin>>n>>k;
        read_(n);
        read_(k);
        for(int i=0;i<n;++i)
        {
        //    cin>>a[i]>>b[i];
        read_(a[i]);
        read_(b[i]);
        }
        sort(a,a+n);
        sort(b,b+n);
    }
    
    long long calculate(long long key)
    {
        long long ret=0;
        for(int i=0;i<n;++i)
        {
            long long tar=key/a[i];
            if(tar*a[i]!=key)tar++;
            long long pos=lower_bound(b,b+n,tar)-b;
            ret+=pos;
        }return ret;
    }
    long long step(long long a,long long b,long long target)
    {
        if(a==b-1)return a;
        long long mid=(a+b)/2;
        long long res=calculate(mid);
        if(res<=target)return step(mid,b,target);
        else return step(a,mid,target);
    
    }
    int main()
    {    
        cin.sync_with_stdio(false);
        init();
        cout<<step(a[0]*b[0],a[n-1]*b[n-1]+1,n*n-k);
        return 0;
    }
  • 相关阅读:
    Linux系统下手把手完成无人值守安装服务
    2019年国际网络安全趋势
    Wi-Fi Mesh网络技术
    如何用nginx在本地把9000端口转发到80端口上
    LAMP架构部署和动态网站环境的配置
    智能校服受到多数学生追捧
    热心网友设计出更美的Windows 10开始菜单
    一起来全面解析5G网络领域最关键的十大技术
    如何跟上时代的步伐进入云世界
    c#写入文件流
  • 原文地址:https://www.cnblogs.com/rikka/p/7389402.html
Copyright © 2011-2022 走看看