HihoCoder

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.

Input

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

Output

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

Sample Input

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

Sample Output

2
1
好多细微的地方,没注意直接WA到炸
首先要让一个集合的校验值尽可能大,可以很直观的感受到要把最大的和最小的配对,第二大的和第二小的配对...题目说的是对区间分段,表示不能破坏原区间的连续性,那么不妨从头分段。段数尽可能少,则每段区间尽可能长,则当前问题转化为:确定左端点后,右端点在满足这一段校验值不超的情况下最大能取多少。朴素的做法是从左端点开始枚举,然后把枚举到的区间排序求校验值进行判断,这样显然是不行的。不那么朴素的做法是二分右端点,但这被卡了(因为每次二分都是从中间位置开始的,但区间右端点最终可能仅比左端点移动了一点)。这时考虑倍增。
开始令p=1,r=l,求出l~r+p的校验值,若校验值<=t且r+p不超过n,则r+=p,p*=2;否则p/=2.同时对于排序,由于l~r已经为有序的,直接排序(l,r+p)会浪费时间,联系归并排序,我们可以只对r+1~r+p排序,然后merge(l,r+p)。这样就能通过了。
#include <bits/stdc++.h>
using namespace std;
int n,m,l,r;
const int maxn=5e5+10;
long long int k,cnt,p;//cnt也要long long 

int a[maxn],b[maxn],c[maxn];
//a存贮原始数据 b存当前排好序的序列 c存最新排好序的序列(注意:只在特定范围内有序) 不能只用一个数组操作 
long long check(int l,int r)
{
    long long cnt=0;
    int i,j,tot=0;
    for(i=0;i<m;i++)
    {
        if(l+i>=r-i)break;
        cnt+=(long long)(c[r-i]-c[l+i])*(c[r-i]-c[l+i]);
    }
    return cnt;
}
void merge(int L1,int R1,int L2,int R2)
{
    int i=L1,j=L2,k;
    for(k=L1;k<=R2;k++)
    {
        if(i>R1)
        {
            c[k]=b[j];
            j++;
         } 
         else if(j>R2)
         {
             c[k]=b[i];
            i++;
         }
         else if(b[i]<b[j])
         {
             c[k]=b[i];
             i++;
         }
         else
         {
             c[k]=b[j];
             j++;
         }
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%d%lld",&n,&m,&k);
        int i;
        cnt=0;
        l=1;//l,r表示当前子区间
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        while(/*r!=n*/l<=n)//当整个区间还没有被划分完时 注意是用l来判断 
        {
            p=1;//??
            b[l]=a[l];//!!
            r=l;
            cnt++;
            while(p!=0)
            {
                //先排序 
                if(r+p>n)//不加会RE  
                {
                    p>>=1;
                    continue;
                }
                int q;
                for(q=r+1;q<=r+p;q++)b[q]=a[q];
                sort(b+r+1,b+r+p+1);//不能是sort(b+r+1+1,b+r+p+1);?? why 
                merge(l,r,r+1,r+p);
                 
                if(check(l,r+p)<=k&&r+p<=n)//如果没有r+p<=n就死循环了 蓝书上没提这一条 
                {
                    r+=p;
                    p<<=1;
                    int z;
                    for(z=l;z<=r;z++)b[z]=c[z];//正式赋值 
                } 
                else p>>=1;
            }
            l=r+1;//准备开始下一段区间 
        }
        cout<<cnt<<endl;
    }
    return 0;
}


原文地址:https://www.cnblogs.com/lipoicyclic/p/12600821.html