zoukankan      html  css  js  c++  java
  • CF561做题

    C题:

    一期思路:我们发现如果x,y满足条件,那么{x,-y} {-x,y} {-x,-y}也满足条件。那么我们可以只讨论|x| |y|是否满足条件,如果满足条件,那么对ans的贡献是|x|出现次数*|y|出现次数。

    于是引申出用二分查找满足条件的值的最靠后的位置,用map保存出现的次数,因为你会发现元素的范围在-10亿到10亿,不能开线性数组来保存出现次数。

    查找到最靠后的位置之后,

    for(j=i+1;j<=ans_pos;++j)  ans = ans + cnt[base]*cnt[ v[j] ];
    但是这样的坏处是

    (1)使用了map,map需要查找时间

    (2)每个都要遍历一遍,复杂度到了O(n^2)。

    (3)容易忽略绝对值相等的情况

      因为一个-x和一个x是能满足条件的,而这个公式很显式的把这种情况排除了,思路就被带偏了。

     综上,即使我解决了(3),if(cnt[base]==2) ++ans;

      还是会因为复杂度到了O(n^2)而超时,那么这时候题解的思路就很好了,压入的是所有的绝对值,这样不仅节约时间,还保证了能考虑到绝对值相等也能满足题意的情况。

    思路正确但是TLE的代码:

    #include <bits/stdc++.h>
    #define pt printf
    #define sc scanf
    #define maxn 200005
    #define ull  unsigned  long long 
    #define inf 0x3f3f3f3f
    using namespace std;
    int N;
    int a[maxn];
    vector<int> v;
    map<int,int> cnt;
    int can(int where,int base)
    {
        int val =  v[where] ;
        if(val%2==0)
        {
            if(base>=val/2) return 1;
            return 0;
        }
        else
        {
            if(base> val/2) return 1;
            return 0;
        }
    }
    int main()
    {
        sc("%d",&N);
        int i,j,x;
        for(i=0;i<N;++i) sc("%d",&a[i]);
        for(i=0;i<N;++i)
        {
            x = abs(a[i]);
            if(cnt.find(x)==cnt.end())
            {
                cnt[x]=1;
                v.push_back(x);
            } 
            else ++cnt[x];
        }
        sort(v.begin(), v.end());
    
        int len = v.size();
    //    for(i=0;i<len;++i) pt("cnt[v[i]]=%d ",cnt[v[i]]);
    //        pt("
    ");
        ull ans = 0;
        //假设大的数是b,小的数是a
        //如果b是偶数,如果a大于等于b的一半那就可以
        //如果b是奇数,如果a大于b的一半那就可以
        for(i=0;i<len;++i)
        {
    //        pt("i=%d
    ",i);
            int base = v[i];
            int l = i+1, r = len - 1, ans_pos = i ;
            //pt("base=%d ,l=%d ,r=%d ,ans_pos=%d 
    ",base,l,r,ans_pos);
            while(l<=r)
            {
                int mid  =  (l+r)>>1;
                int status = can(mid,base);
                if(status==1) 
                {
                    ans_pos = mid;
                    l = mid + 1;
                }
                else
                {
                    r = mid - 1;
                }
            }
            for(j=i+1;j<=ans_pos;++j)
            {
                ans = ans + cnt[base]*cnt[ v[j] ];
            }
            if(cnt[base]==2) ++ans;
        }
        pt("%llu
    ",ans);
        return 0;
    }
    View Code

    AC的代码:满足条件的函数我分了奇偶讨论,但是只要   小的数*2>=大的数   就可以了。

    #include <bits/stdc++.h>
    #define pt printf
    #define sc scanf
    #define maxn 200005
    #define ull  unsigned  long long 
    #define inf 0x3f3f3f3f
    using namespace std;
    int N;
    int a[maxn];
    vector<int> v;
    int can(int where,int base)
    {
        int val =  v[where] ;
        if(val%2==0)
        {
            if(base>=val/2) return 1;
            return 0;
        }
        else
        {
            if(base> val/2) return 1;
            return 0;
        }
    }
    int main()
    {
        sc("%d",&N);
        int i,j,x;
        for(i=0;i<N;++i) sc("%d",&a[i]);
        for(i=0;i<N;++i)
        {
            x = abs(a[i]);
            v.push_back(x);
        }
        sort(v.begin(), v.end());
        int len = N;
    //    for(i=0;i<len;++i) pt("cnt[v[i]]=%d ",cnt[v[i]]);
    //        pt("
    ");
        ull ans = 0;
        //假设大的数是b,小的数是a
        //如果b是偶数,如果a大于等于b的一半那就可以
        //如果b是奇数,如果a大于b的一半那就可以
        for(i=0;i<len;++i)
        {
    //        pt("i=%d
    ",i);
            int base = v[i];
            int l = i+1, r = len - 1, ans_pos = i ;
            //pt("base=%d ,l=%d ,r=%d ,ans_pos=%d 
    ",base,l,r,ans_pos);
            while(l<=r)
            {
                int mid  =  (l+r)>>1;
                int status = can(mid,base);
                if(status==1) 
                {
                    ans_pos = mid;
                    l = mid + 1;
                }
                else
                {
                    r = mid - 1;
                }
            }
            ans += (ans_pos-i);
        }
        pt("%llu
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Link assemblies causes app crashes if you have an EditText
    Link causes xamarin Android binding library project to crash
    Linux系统目录结构详解
    Centos Linux系统优化二
    Centos Linux系统优化一
    rm命令详解
    mv命令详解
    cp命令详解
    echo命令详解
    touch命令详解
  • 原文地址:https://www.cnblogs.com/lighten-up-belief/p/10885414.html
Copyright © 2011-2022 走看看