hiho 1384 Genius ACM(倍增+归并)

ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
#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.

  1. 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

题目大意:给定一个n个正数的序列,定义检查值给一段序列中m对数的差的平方和,如果不足m对,则取尽量多对,当检查值小于等于k时这段序列就通过检查。求最少把这n个数分为几段连续的序列使得每一段都通过检查。
题解:可以容易发现检查值最大的时候,为(最大数-最小数)2+(次大数-次小数)2…贪心地从头开始倍增区间,当通过检查时继续倍增区间,不通过时倍减区间,直到无法倍增为止。在求检查值的时候不直接采取对要求的区间进行排序,而是采取归并的方式,因为倍增前的区间已经是有序的,我们只要对新增的区间进行排序即可,然后对两个区间进行归并(O(n)),当通过检查时我们更新旧区间+新区间(使其变为刚刚归并好的区间,使其变成新的旧区间,再进行新一轮的倍增),整个复杂度O(nlog2n)

#include
#define ll long long 
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
#define sqr(a) (a)*(a)
using namespace std;
const int maxn = 5e5+5;
int T,n,m,a[maxn],buf[maxn],b[maxn];
ll k;
template<typename T> inline void R(T &x) {
	char ch = getchar(); x = 0;
	for (; ch<'0'; ch = getchar());
	for (; ch >= '0'; ch = getchar()) x = x * 10 + ch - '0';
} 
inline void merge(int l,int r,int m){
	int i=l,j=m+1;
	for(int k=l;k<=r;k++){
		if(j>r || i<=m &&b[i]<b[j])buf[k]+=b[i++];
		else buf[k]=b[j++];
	}
}
ll calc(int l,int r){
	ll res=0;			
	fo(i,0,m-1){
		if(l+i>r-i)break;
		res += sqr(1ll*buf[l+i]-1ll*buf[r-i]);
	}
	return res;
}
void solve(){
	int l=1,r=l;
	int ans=0;
	while(l<=n){
		ans++;
		int p=1;r=l;// 重新赋值p=1,r=l(WA了无数遍检查不错错误,切忌r=L(非1)) 
		ll tmp;
		b[l]=a[l];// 赋值第一个数 
		while(p){
			if(r+p>n){p>>=1;continue;}// 倍增区间太长倍减		 
			fo(i,r+1,r+p) b[i]=a[i];  // 赋值新区间 
			sort(b+r+1,b+1+r+p);      // 倍增区间排序
			merge(l,r+p,r);           // 归并新旧区间			
			tmp = calc(l,r+p);		  // 计算新区间的校检值	
			if(tmp<=k){ // 合格倍增 
				fo(i,l,r+p)b[i]=buf[i]; // 正式排序好的buf赋值给b
				r+=p;p<<=1;
			}else{ // 不合格倍减 
				p>>=1;
			}
		}
		l = r+1;
	}	
	printf("%d\n",ans);
} 
int main(){
	R(T);
	while(T--){
		R(n);R(m);R(k);
		fo(i,1,n)R(a[i]);
 		solve();
	}
}

你可能感兴趣的:(倍增,ACM算法日常)