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;
}

 

posted @ 2019-08-13 18:54  不会fly的pig  阅读(258)  评论(0编辑  收藏  举报