Division HDU

//将含有N个元素的一个集合分成M个子集,使得每个子集的最大值与最小值平方差的和最小。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e4+50;
const int maxm = 5e3+50;
ll dp[maxn][maxm] ,v[maxn] ;
int n ,m ;
int q[maxn] ,r,l ;
ll getdp(int i,int j,int k) {
	return dp[k][j-1] + (v[i] - v[k + 1]) * (v[i] - v[k + 1]);
}
ll y(int j,int k,int q) {
	return dp[k][j-1] + v[k + 1] * v[k + 1] - (dp[q][j-1] + v[q + 1] * v[q + 1]);
}
ll x(int k,int q) {
	return 2 * ( v[k + 1] - v[q + 1] );
}
int main() {
	int t ,ncase = 1 ;
	cin>>t;
	while(t--) {
		scanf("%d %d",&n ,&m );
		for (int i = 1; i<=n; i++) 
			scanf("%lld",&v[i] );
		sort(v + 1 ,v + n + 1 );
		for (int i = 1; i<=n; i++) 
			dp[i][1] = (v[i] - v[1]) * (v[i] - v[1]);
		for (int i = 2; i<=m; i++) {
			l = r = 0;
			q[0] = i - 1;
			for (int j = i; j<=n; j++) {
				while(l  < r && y(i ,q[l+1] ,q[l]) < x(q[l+1] ,q[l]) * v[j] ) 
					l ++;
				dp[j][i] = getdp(j ,i ,q[l] );
				while(l  < r && y(i ,q[r] ,q[r-1]) * x(j ,q[r]) >= y(i ,j ,q[r]) * x(q[r] ,q[r-1]) ) 
					r --;
				q[++r] = j;
			}
		}
		printf("Case %d: ",ncase++);
		printf("%lld
",dp[n][m]);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12519135.html