HihoCoder - 1384 Genius ACM(倍增)

版权声明:选经典题目,写精品文章. https://blog.csdn.net/nka_kun/article/details/82632471

1384 : Genius ACM

时间限制:3000ms
单点时限:3000ms
内存限制:256MB

描述
Advanced CPU Manufacturer (ACM) is one of the best CPU manufacturer in the world. Every day, they manufacture n CPU chips and sell them all over the world.

As you may know, each batch of CPU chips must pass a quality test by the QC department before they can be sold. The testing procedure is as follows:

1) Randomly pick m pairs of CPU chips from the batch of chips (If there are less than 2m CPU chips in the batch of chips, pick as many pairs as possible.)

2) For each pair, measure the Relative Performance Difference (RPD) between the two CPU chips. Let Di be the RPD of the i-th pair

3) Calculate the Sqared Performance Difference (SPD) of the batch according to the following formula:

SPD=∑Di2

If there are only 1 CPU in a batch, then the SPD of that batch is 0.

4) The batch of chips pass the test if and only if SPD≤k, where k is a preseted constant

Usually they send all the n CPU chips as a single batch to the QC department every day. As one of the best CPU manufacturer in the world, ACM never fail the test. However, with the continuous improvement of CPU performance, they find that they are at risk!

Of course they don’t want to take any risks. So they make a decision to divide the n chips into several batches to ensure all of them pass the test. What’s more, each batch should be a continuous subsequence of their productions, otherwise the QC department will notice that they are cheating. Quality tests need time and money, so they want to minimize the number of batches.

Given the absolute performance of the n chips P1 … Pn mesured by ACM in order of manufacture, your task is to determine the minimum number of batches to ensure that all chips pass the test. The RPD of two CPU chips equals to the difference of their absolute performance.

输入
The first line contains a single integer T, indicating the number of test cases.

In each test case, the first line contains three integers n, m, k. The second line contains n integers, P1 … Pn.

T≤12
1≤n,m≤5×105
0≤k≤1018
0≤Pi≤220

输出
For each test case, print the answer in a single line.

样例输入
2
5 1 49
8 2 1 7 9
5 1 64
8 2 1 7 9
样例输出
2
1

题意: 给定一个整数 m,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 m 对数(即 2*m 个数,不能重复使用集合中的数,如果 S 中的整 数不够 m 对,则取到不能取为止),使得“每对数的差的平方”之和最大,这个最大值 就称为集合 S 的“校验值”。 现在给定一个长度为 n 的数列 A 以及m、k。我们要把 A 分成若干段,使得 每一段的“校验值”都不超过 k。求最少需要分成几段。

思路: 首先可以明确的是,我们想每一段尽量长.所以就有一个暴力方法,每次从这段的起点开始,一个一个往数列里加,加一个判断一次,直到不能加了为止,也就是这段结束了,可是新的一段. 考虑如何优化,我们每次可以不止加一个,所以就有这样的倍增方法.从这段起点开始,加入len个,判断一个,如果合法,就把这段右端点更新为r+len,同时len*2,否则 len/2,直到不能添加,这段结束.

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e6+5;
const double eps = 1e-12;
const int inf = 0x3f3f3f3f;
map<int,int>::iterator it;

int n,m;
ll k;

ll a[maxn],b[maxn],c[maxn],d[maxn];

bool merge(ll b[],int l1,ll c[],int l2)
{
    int p1 = 1,p2 = 1,cnt = 0;
    while(p1<= l1||p2<= l2)
    {
        if(p1> l1)
            d[++cnt] = c[p2++];
        else if(p2> l2)
            d[++cnt] = b[p1++];
        else
        {
            if(b[p1]< c[p2])
                d[++cnt] = b[p1++];
            else
                d[++cnt] = c[p2++];     
        }
    }

    ll sum = 0;
    for(int i = 1;i<= m&&cnt-i+1> i;i++)
        sum+= (d[cnt-i+1]-d[i])*(d[cnt-i+1]-d[i]);

    if(sum> k) return 0;
    for(int i = 1;i<= cnt;i++)
        b[i] = d[i];
    return 1;
}

int solve(int x)
{
    int l = x,r = x,len = 1;
    b[1] = a[x];
    while(len> 0)
    {
        if(r+len> n) len = n-r;
        for(int i = r+1;i<= r+len;i++)
            c[i-r] = a[i];

        sort(c+1,c+len+1);

        if(merge(b,r-l+1,c,len))
            r+= len,len<<= 1;
        else
            len>>= 1;
        if(r>= n) break;
    }

    return r;
}

int main()
{
    int t;
    cin>>t;

    while(t--)
    {
        scanf("%d %d %lld",&n,&m,&k);
        for(int i = 1;i<= n;i++)
            scanf("%lld",&a[i]);

        int ans = 0;
        for(int i = 1;i<= n;i++)
        {
            i = solve(i);
            ans++;
        }

        printf("%d\n",ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/82632471
今日推荐