hdu2829之二维斜率优化DP

T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in the Arabian theater and led a group of Arab nationals in guerilla strikes against the Ottoman Empire. His primary targets were the railroads. A highly fictionalized
version of his exploits was presented in the blockbuster movie, "Lawrence of Arabia".

You are to write a program to help Lawrence figure out how to best use his limited resources. You have some information from British Intelligence. First, the rail line is completely linear---there are no branches, no spurs. Next, British Intelligence has assigned
a Strategic Importance to each depot---an integer from 1 to 100. A depot is of no use on its own, it only has value if it is connected to other depots. The Strategic Value of the entire railroad is calculated by adding up the products of the Strategic Values
for every pair of depots that are connected, directly or indirectly, by the rail line. Consider this railroad:

Its Strategic Value is 4*5 + 4*1 + 4*2 + 5*1 + 5*2 + 1*2 = 49.

Now, suppose that Lawrence only has enough resources for one attack. He cannot attack the depots themselves---they are too well defended. He must attack the rail line between depots, in the middle of the desert. Consider what would happen if Lawrence attacked
this rail line right in the middle:

The Strategic Value of the remaining railroad is 4*5 + 1*2 = 22. But, suppose Lawrence attacks between the 4 and 5 depots:

The Strategic Value of the remaining railroad is 5*1 + 5*2 + 1*2 = 17. This is Lawrence‘s best option.

Given a description of a railroad and the number of attacks that Lawrence can perform, figure out the smallest Strategic Value that he can achieve for that railroad.

Input

There will be several data sets. Each data set will begin with a line with two integers, n and m. n is the number of depots on the railroad (1≤n≤1000), and m is the number of attacks Lawrence has resources for (0≤m<n). On the next line will be n integers, each
from 1 to 100, indicating the Strategic Value of each depot in order. End of input will be marked by a line with n=0 and m=0, which should not be processed.

Output

For each data set, output a single integer, indicating the smallest Strategic Value for the railroad that Lawrence can achieve with his attacks. Output each integer in its own line.

Sample Input

4 1
4 5 1 2
4 2
4 5 1 2
0 0

Sample Output

17
2

题意:n个数分成m段,每段的和是该段内的数两两之间的和,求最小值

/*分析:
假定dp[i][j]表示前i个数分成j段的最小值
cost[i]表示从1~i的数两两相乘的总和
sum[i]表示前i个数的和
则:
dp[i][j]=Min(dp[k][j-1]+cost[i]-cost[k]-sum[k]*(sum[i]-sum[k]))
=>dp[i][j]=dp[k][j-1]+cost[i]-cost[k]-sum[i]*sum[k]+sum[k]*sum[k]
由于有sum[i]*sum[k]这一项,所以不可能用单调队列维护
-cost[k]-sum[i]*sum[k]+sum[k]*sum[k]的最小值
所以我们要把sum[i]独立出来以便求维护单调队列是和i无关
如今我们须要找出最优的k,
令k2<k时k时最优的,即前k个数k为最优的取值
所以满足:
dp[k][j-1]+cost[i]-cost[k]-sum[i]*sum[k]+sum[k]*sum[k]
<=dp[k2][j-1]+cost[i]-cost[k2]-sum[i]*sum[k2]+sum[k2]*sum[k2]
=>(dp[k][j-1]-cost[k]+sum[k]*sum[k]-(dp[k2][j-1]-cost[k2]+sum[k2]*sum[k2]))/(sum[k]-sum[k2])<=sum[i]
设:
y1=dp[k][j-1]-cost[k]+sum[k]*sum[k]
x1=sum[k]
y2=dp[k2][j-1]-cost[k2]+sum[k2]*sum[k2]
x2=sum[k2]
所以变成:
(y2-y1)/(x2-x1)
即两点之间的斜率!
对于这个斜率我们怎么来寻找关系维护?
假定k点之前k最优且k点在单调队列的首位置
如今对于k+1点
首先对于队列中的点更新k+1之后的点能否比k,k+1..更优,即更新最长处(由于sum[k+1]添加了所以能够更新最长处)
然后对于点k+1与队列中最后一个点的斜率必须是整个队列中斜率最大的,即保持斜率单调添加
为什么?由于假如k+1与k的斜率比k与k-1的斜率更低,
则随着sum[k+x]添加,k+1会首先更优于k,所以不须要k点,仅仅须要比較k+1与k-1的点的优先值
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std;

const int MAX=1000+10;
int n,m,index,head,tail;
int s[MAX],q[MAX];
int dp[MAX][2],cost[MAX],sum[MAX];//dp採用滚动数组 

int GetY(int k,int k2){
	return dp[k][index^1]-cost[k]+sum[k]*sum[k]-(dp[k2][index^1]-cost[k2]+sum[k2]*sum[k2]);
}

int GetX(int k,int k2){
	return sum[k]-sum[k2];
}

void DP(){
	index=0;
	memset(dp,0,sizeof dp);
	for(int i=1;i<=n;++i)dp[i][index]=cost[i];
	for(int j=1;j<=m;++j){//分成j段,j作为第一层循环才用滚动数组
		index=index^1;
		head=tail=0;
		q[tail++]=0;
		for(int i=1;i<=n;++i){
			while(head+1<tail && GetY(q[head+1],q[head])<=GetX(q[head+1],q[head])*sum[i])++head;
			dp[i][index]=dp[q[head]][index^1]+cost[i]-cost[q[head]]-sum[i]*sum[q[head]]+sum[q[head]]*sum[q[head]];
			while(head+1<tail && GetY(i,q[tail-1])*GetX(q[tail-1],q[tail-2])<=GetY(q[tail-1],q[tail-2])*GetX(i,q[tail-1]))--tail;
			q[tail++]=i;
		}
	}
}

int main(){
	while(~scanf("%d%d",&n,&m),n+m){
		for(int i=1;i<=n;++i)scanf("%d",&s[i]);
		for(int i=1;i<=n;++i)sum[i]=sum[i-1]+s[i];
		memset(cost,0,sizeof cost);
		for(int i=1;i<=n;++i){
			for(int j=i+1;j<=n;++j)cost[j]+=s[i]*s[j];
		}
		for(int i=1;i<=n;++i)cost[i]+=cost[i-1];
		DP();
		printf("%d\n",dp[n][index]);
	}
	return 0;
} 
时间: 2024-12-15 17:30:51

hdu2829之二维斜率优化DP的相关文章

hdu3480之二维斜率优化DP

Division Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 999999/400000 K (Java/Others) Total Submission(s): 2664    Accepted Submission(s): 1050 Problem Description Little D is really interested in the theorem of sets recently. There's a pro

hdu3480二维斜率优化DP

Division Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 999999/400000 K (Java/Others) Total Submission(s): 2664    Accepted Submission(s): 1050 Problem Description Little D is really interested in the theorem of sets recently. There's a pro

hdu3669之二维斜率DP

Cross the Wall Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 4176    Accepted Submission(s): 748 Problem Description "Across the Great Wall, we can reach every corner in the world!" No

HDU2829 Lawrence(斜率优化dp)

学了模板题之后上网搜下斜率优化dp的题目,然后就看到这道题,知道是斜率dp之后有思路就可以自己做不出来,要是不事先知道的话那就说不定了. 题意:给你n个数,一开始n个数相邻的数之间是被东西连着的,对于连着的一片的数,它们的价值就是两两乘积的和.所以4 5 1 2一开始就是4*5+4*1+4*2+5*1+5*2+1*2... 注意到两两乘积的和其实是可以这么算的((a1+a2+a3+..an)^2-(a1^2+a2^2+....))/2.现在我可以在数与数之间切m刀,问切完之后的最小价值是多少.

BZOJ 3675 APIO2014 序列切割 斜率优化DP

题意:链接 方法:斜率优化DP 解析:这题BZ的数据我也是跪了,特意去网上找到当年的数据后面二十个最大的点都过了.就是过不了BZ. 看到这道题自己第一发DP是这么推得: 设f[i][j]是第j次分第i个的最大得分. 那么会推出来f[i][j]=max(f[k][j?1]+sum[i k]?sum[1 k?1]或(sum[k i]?sum[i+1 n]))然后我发现这个式子的复杂度非常高暂且不说.就光那个或的讨论就非常费劲. 于是想了想就放弃了这个念头.中规中矩的去想. 依照以往的思路设出状态f[

BZOJ 3675 APIO2014 序列分割 斜率优化DP

题意:链接 方法:斜率优化DP 解析:这题BZ的数据我也是跪了,特意去网上找到当年的数据后面二十个最大的点都过了,就是过不了BZ. 看到这道题自己第一发DP是这么推得: 设f[i][j]是第j次分第i个的最大得分. 那么会推出来f[i][j]=max(f[k][j?1]+sum[i k]?sum[1 k?1]或(sum[k i]?sum[i+1 n]))然后我发现这个式子的复杂度很高暂且不说,就光那个或的讨论就很费劲. 于是想了想就放弃了这个念头,中规中矩的去想. 按照以往的思路设出状态f[i]

【转】斜率优化DP和四边形不等式优化DP整理

当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环 (一重循环跑状态 i,一重循环跑 i 的所有子状态)这样的时间复杂度是O(N^2)而 斜率优化或者四边形不等式优化后的DP 可以将时间复杂度缩减到O(N) O(N^2)可以优化到O(N) ,O(N^3)可以优化到O(N^2),依次类推 斜率优化DP和四边形不等式优化DP主要的原理就是利用斜率或者四边形不等式等数学方法 在所有要判断的子状态中迅速做出判断,所以这里的优化其实是省去了枚举

hdu3507,斜率优化dp

斜率优化\(dp\)入门题. \(ProblemLink\) 先从\(n^2\)的\(dp\)开始 设\(S_i=\sum_{i=1}^n a_i\) \(f_i\)为输出前\(i\)个的最小代价. 显然有\(f_i=min(f_j+(S_i-S_j)^2+M)(j<k)\) 考虑对于点i.j比k\((j>k)\)更优当且仅当 \(f_j+(S_i-S_j)^2<f_k+(S_i-S_k)^2\) \(f_j+S_j^2-2S_iS_j<f_k+S_k^2-2S_iS_k\) \(

斜率优化dp(玩具装箱)

斜率优化dp 斜率优化dp的思想是数形结合,将各种决策点反映在平面直角坐标系中,然后通过斜率进行优化 做法首先将这道题的$n^2$的dp 算法写出来然后将其暴力展开如:f(i)=min(f(j)+(s[i]-s[j]+i-j-1-l)^2)令s[i]=s[i]+i,l=l+1原式变为$f(i)=min(f(j)+(s[i]-s[j]-l)^2)暴力展开后是长这样的:f(i)=f(j)+s[i]^2+s[j]^2+l^2-2s[i]s[j]-2s[i]l+2s[j]l我们可以将这个式子的右边转化为