您的位置:首页 > 其它

HDU 2829 Lawrence(斜率DP)

2015-09-18 15:05 405 查看

题意:给n(1<=n<=1000)个数,要将其分成m + 1(0<=m<n)组,要求每组数必须是连续的而且要求得到的价值最小。一组数的价值定义为该组内任意两个数乘积之和,如果某组中仅有一个数,那么该组数的价值为0。

思路:设sv[i][j]为区间[i,j]之间的价值,那么我们可以得到一个状态转移方程

dp[i][j] = min(d[i-1][k]+sv[k+1][j]),dp[i][j]表示前j个数放i个间隔的最小值,

可以发现如果不优化的话时间复杂度为O(n*n*n)无法承受,我们要优化首先要把sv[k+1][j]转化成一个包含k和包含j和包含jk的多项式的乘积,

可以发现sv[k+1][j] = sv[1][j] - sv[1][k] - sum[k]*(sum[j]-sum[k]),然后我们可以发现出现了只和k,j有关的项和包含j的项乘以包含k的项,那么我们就可以用斜率DP来优化了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 1000 + 5;
int n, m;
int a[MAXN];
LL Sum[MAXN], sv[MAXN][MAXN], dp[MAXN][MAXN];
int Q[MAXN], h, t;
LL getY(int k, int j, int i) {
	return dp[i][k]-sv[1][k]+Sum[k]*Sum[k] - dp[i][j]+sv[1][j]-Sum[j]*Sum[j];
} 
LL getX(int k, int j) {
	return Sum[k]-Sum[j];
}
int main() {
    //freopen("input.txt", "r", stdin);
	while(scanf("%d%d", &n, &m)==2 && n) {
		int tmp;
		for(int i = 1; i <= n; i++) scanf("%d", &a[i]), Sum[i]=Sum[i-1]+a[i];
		for(int i = 1; i <= n; i++) {
			for(int j = i+1; j <= n; j++) sv[i][j] = sv[i][j-1]+a[j]*(Sum[j-1]-Sum[i-1]);
		}
		for(int j = 1; j <= n; j++) dp[0][j] = sv[1][j];
		for(int i = 1; i <= m; i++) {
			h = 1, t = 0;
			Q[++t] = i;
			for(int j = i+1; j <= n; j++) {
				//if(i==2&&j==4) cout << Q[t] << endl;
				while(t>h && getY(Q[h+1], Q[h], i-1)<=Sum[j]*getX(Q[h+1], Q[h])) h++;
				//if(i==2&&j==4) cout << getY(Q[h+1], Q[h], i-1) << endl << Sum[j]*getX(Q[h+1], Q[h]) << endl;
				//if(i==2&&j==4) cout << Q[h] << endl;
				dp[i][j] = dp[i-1][Q[h]] + sv[Q[h]+1][j];
				while(t>h && getY(j, Q[t], i-1)*getX(Q[t], Q[t-1])<=getY(Q[t],Q[t-1], i-1)*getX(j, Q[t])) t--;
				Q[++t] = j;
				//cout << i << " " << j << " " << dp[i][j] << endl;
			}
		} 
		cout << dp[m]
 << endl; 
	}
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: