• AcWing 109 天才ACM(倍增)


    题目链接

    基本思路

      这道题最基本的想法就是一次寻找每个区间,对于每个区间,用二分来判定其最大长度。每次check的时候,对区间排序,不断取出不大于m对最大值与最小值求值即可。
      然后你就喜提TLE了,笑如果用倍增来代替二分的话能过,不过其实倍增最坏复杂度和二分一样,应该是数据没有刻意来卡倍增。下面先给出倍增的代码。

    代码

    const int maxn = 5e5+10;
    int t,n,m,arr[maxn],tmp[maxn]; ll T;
    ll check(int l, int r) {
        for (int i = l; i<r; ++i) tmp[i] = arr[i];
        sort(tmp+l,tmp+r);
        ll sum = 0; int stp = 0;
        for (int i = 0; i < m && l+i<r-i-1; i ++ )
            sum += (ll)(tmp[l+i]-tmp[r-i-1])*(tmp[l+i]-tmp[r-i-1]);
        return sum;
    }
    int main(){
        scanf("%d",&t);
        while(t--) {
            scanf("%d%d%lld",&n,&m,&T);
            for (int i = 0; i<n; ++i) scanf("%d",&arr[i]);
            int st = 0, ed = 0, ans = 0;
            while(ed<n) {
                int len = 1;
                while(len) {
                    if (ed+len<=n && check(st,ed+len)<=T) {
                        ed += len; len <<= 1;
                    }
                    else len >>= 1;
                }
                ++ans;
                st = ed;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    进一步优化

      我们在倍增的时候发现一个问题,每次枚举区间的时候,它的长度都是在递增的,而我们每次check都重复的对区间前部进行的排序,所以就有了优化空间。
      我们可以每次只对新增的部分排序,因为前面的部分有序,所以就可以像归并排序那样讲两段区间合并成一个区间,这样减少了排序长度,就能获得更快的速度。

    代码

    const int maxn = 5e5+10;
    int t,n,m,arr[maxn],tmp[maxn],tmp2[maxn]; ll T;
    bool check(int l, int r, int len) {
        for (int i = l; i<r+len; ++i) tmp[i] = arr[i];
        sort(tmp+r,tmp+r+len);
        int st1 = l, st2 = r, tot = l;
        while(st1<r || st2<r+len) {
            if (st2>=r+len || (st1<r&&tmp[st1]<=tmp[st2])) tmp2[tot++] = tmp[st1++];
            else tmp2[tot++] = tmp[st2++];  
        }
        ll sum = 0;
        for (int i = 0; i < m && l+i<r+len-i-1; ++i)
            sum += (ll)(tmp2[l+i]-tmp2[r+len-i-1])*(tmp2[l+i]-tmp2[r+len-i-1]);
        return sum<=T;
    }
    int main(){
        scanf("%d",&t);
        while(t--) {
            scanf("%d%d%lld",&n,&m,&T);
            for (int i = 0; i<n; ++i) scanf("%d",&arr[i]);
            int st = 0, ed = 0, ans = 0;
            while(ed<n) {
                //cout << st << ' ' << ed << endl;
                int len = 1;
                while(len) {
                    if (ed+len<=n && check(st,ed,len)) {
                        for (int i = ed; i<ed+len; ++i) arr[i] = tmp2[i];
                        ed += len; len <<= 1;
                    }
                    else len >>= 1;
                }
                ++ans;
                st = ed; 
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    安装oracle11g 并且开启APEX 安装
    爬虫基础
    深度优先广度优先
    部署静态页面到nginx
    Nginx 实现端口转发
    五步教你实现使用Nginx+uWSGI+Django方法部署Django程序
    Please select Android SDK解决办法
    android与JS交互,互相调用方法,跳转到网页
    Android:你要的WebView与 JS 交互方式 都在这里了
    Android与js交互拍照上传资料
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/13372530.html
Copyright © 2020-2023  润新知