zoukankan      html  css  js  c++  java
  • AcWing:109. 天才ACM(倍增 + 归并排序)

    给定一个整数 MM,对于任意一个整数集合 SS,定义“校验值”如下:

    从集合 SS 中取出 MM 对数(即 2M2∗M 个数,不能重复使用集合中的数,如果 SS 中的整数不够 MM 对,则取到不能取为止),使得“每对数的差的平方”之和最大,这个最大值就称为集合 SS 的“校验值”。

    现在给定一个长度为 NN 的数列 AA 以及一个整数 TT。

    我们要把 AA 分成若干段,使得每一段的“校验值”都不超过 TT。

    求最少需要分成几段。

    输入格式

    第一行输入整数 KK,代表有 KK 组测试数据。

    对于每组测试数据,第一行包含三个整数 N,M,TN,M,T 。

    第二行包含 NN 个整数,表示数列A1,A2ANA1,A2…AN。

    输出格式

    对于每组测试数据,输出其答案,每个答案占一行。

    数据范围

    1K121≤K≤12,
    1N,M5000001≤N,M≤500000,
    0T10180≤T≤1018,
    0Ai2200≤Ai≤220

    输入样例:

    2
    5 1 49
    8 2 1 7 9
    5 1 64
    8 2 1 7 9
    

    输出样例:

    2
    1

    算法:倍增 + 归并

    注意:本题不能直接用sort排序,会时间超限,必须用归并来优化排序。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 5e5+7;
    
    ll n, m, k;
    ll arr[maxn];
    ll a[maxn];
    ll b[maxn];
    
    void merge(int l, int mid, int r) {
        int i = l, j = mid;
        int t = l;
        while(i < mid || j <= r) {
            if((i < mid && a[i] <= a[j]) || j > r) {
                b[t++] = a[i++];
            } else {
                b[t++] = a[j++];
            }
        }
    }
    
    bool check(int l, int mid, int r) {
        for(int i = mid; i <= r; i++) {
            a[i] = arr[i];
        }
        sort(a + mid, a + r + 1);   //在mid之前的数都是有序的,从mid开始就是copy的arr数组中的值,所以需要变成有序才能归并
        merge(l, mid, r);
        ll sum = 0;
        for(int i = l, j = r, cnt = 0; cnt < m && i < j; i++, j--, cnt++) {
            sum += (b[j] - b[i]) * (b[j] - b[i]);
        }
        if(sum <= k) {
            for(int i = l; i <= r; i++) {
                a[i] = b[i];
            }
            return true;
        } 
        return false;
    }   
    
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            cin >> n >> m >> k;
            for(int i = 1; i <= n; i++) {
                cin >> arr[i];
            }
            int l = 1, r = 1, h = 1;
            a[l] = arr[l];
            int ans = 0;
            while(r <= n) {
                if(h == 0) {    //当长度不可取的时候,就开始匹配下一段
                    ans++;
                    r++;
                    l = r;
                    h = 1;
                    a[l] = arr[l];
                } else if(r + h <= n && check(l, r + 1, r + h)) {
                    r += h;
                    h *= 2;
                    if(r == n) {
                        break;
                    }
                } else {
                    h /= 2;
                }
            }
            if(r == n) {
                ans++;
            }
            cout << ans << endl;
        }
        return 0;
    }
  • 相关阅读:
    ETF上线技术要素
    oracle修改用户的schema
    list
    交易系统分类OMS/EMS
    类的大小2
    webpack5教程
    vue配置stylelint教程
    提高国内访问 GitHub 的速度的 9 种方案
    git常见的操作
    img 图像底部留白的原因以及解决方法
  • 原文地址:https://www.cnblogs.com/buhuiflydepig/p/11347820.html
Copyright © 2011-2022 走看看