【BZOJ1911】【Apio2010】特别行动队,斜率优化DP裸题(斜率有单调性)

题解:

首先裸dp方程为:

F(x)=a*x*x+b*x+c;  sum为前缀和

f[i]=f[j]+F(sum[i]-sum[j]);

然后拆开后把带j的放一边,带i的放一边,形成y=kx+b的形式,使y和x都含j不含i,k和b都含i不含j。

得:f[j]+asum[j]*sum[j]-b*sum[j]=2*a*sum[i]*sum[j]+f[i]-a*sum[i]*sum[i]-b*sum[i]-c;

然后有:y=kx+b;

y=f[j]+asum[j]*sum[j]-b*sum[j];

x=sum[j];

k=2*a*sum[i];

b=f[i]-a*sum[i]*sum[i]-b*sum[i]-c;

然后显然可以观察到,每个j处理出来一个x和y,则可以在坐标系中进行表示。

而若有一个i,则又可以处理出“k”,那么这样就可以算出来b的值。

而已知i,通过b的值我们又可以算出来f[i]的值。

b为截距,那么本题中b与f[i]就成正比。我们可以先画出一个斜率为k,经过j抽象出来的点J的直线帮助理解。

显然,这个截距需要尽量大以保证答案。

随后我们需要根据点维护一个凸包,可以脑补一下,凸包内的点不可能更优(这个不细说了),而我们要找的则是一个凸点P,使得我们先把直线放在无限高处,然后向下平移,接触到的凸包上的第一个点。

通过画图可以直观地发现:斜率为k的直线经过点P时有对于当前“i”的最大截距。

即对于当前“i”,这个P代表的“j”是动规方程f[i]=f[j]+F(sum[i]-sum[j])的可以转移来的最优的j,

即任意通过k(k!=j)转移来的f[i]都要小于通过j转移过来的f[i]。

一般情况下我们可以二分来找到这个凸点P,但是有些时候斜率满足单调性,我们就可以利用类似单调队列的维护方法对凸包进行维护,如本题,一旦队列头的一点对于i处理出来的斜率k劣于队列中的第二个点,就把头出队,这样出队操作完成后就可以取队头为i的最优决策j了。

然后决策完成后我们就得到了f[i],就又可以处理出i的“x”和“y”,这时再把它加入到凸包中就好了。

呃,凸包就不多说了。

贴代码,这个代码挺清晰的~~~(维护的上凸包。。。。)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1001000
#define X(x) (sum[x])
#define Y(x) (f[x]+a*sum[x]*sum[x]-b*sum[x])
#define K(x) (2*a*sum[x])
#define F(x) (a*x*x+b*x+c)
using namespace std;
int L,R,n,a,b,c;
long long sum[N],f[N];
struct Point
{
	long long x,y;
	int id;
	Point(long long _x,long long _y,int _id):x(_x),y(_y),id(_id){}
	Point(){}
}que[N],now;
inline long long xmul(Point i,Point j,Point k){return (j.x-k.x)*(i.y-k.y)-(j.y-k.y)*(i.x-k.x);}
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	scanf("%d%d%d%d",&n,&a,&b,&c);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&sum[i]),sum[i]+=sum[i-1];
		k=K(i);
		while(L<R&&que[L].y-k*que[L].x<que[L+1].y-k*que[L+1].x)L++;
		f[i]=f[que[L].id]+F((sum[i]-sum[que[L].id]));
		now=Point(X(i),Y(i),i);
		while(L<R&&xmul(now,que[R],que[R-1])>=0)R--;
		que[++R]=now;
	}
	cout<<f[n]<<endl;
	return 0;
}
时间: 2024-11-03 17:30:13

【BZOJ1911】【Apio2010】特别行动队,斜率优化DP裸题(斜率有单调性)的相关文章

bzoj1911[Apio2010]特别行动队 斜率优化dp

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 5057  Solved: 2492[Submit][Status][Discuss] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT dp[i]=dp[j]+a*x*x+b*x+cx=sum[i]-sum[j] 证明单调性假设对于i点 k<j且j的决策

BZOJ1911 [Apio2010]特别行动队 - 动态规划 - 斜率优化

欢迎访问~原文出处--博客园-zhouzhendong&AK 去博客园看该题解 题目传送门 题意概括 把一个整数序列划分成任意连续的段,使得划分出来的每一段的价值和最大. 对于某一段,价值的计算公式为 V=ax^2+bx+c,其中 x 为当前段的数值和. 题解 这题是博主大蒟蒻的第一道斜率优化DP题-- C++:while (1) 懵逼++; Pascal:while (true) do inc(懵逼); 本题首先一看就是 DP 题. 但是一看 1<=n<=1000000,-5<

Bzoj1911 [Apio2010]特别行动队

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3969  Solved: 1873 Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT Source 斜率优化DP f[分组末尾]=最优解 f[i] = max{f[j]+A(s[i]-s[j])^2+B(s[i]-s[j])+C}  (0<=j<i)

bzoj1911 [Apio2010]特别行动队commando

题目链接 斜率优化 1 #include<cstdio> 2 #include<cstdlib> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #define re(i,l,r) for(int i=(l);i<=(r);i++) 7 using namespace std; 8 typedef long long LL; 9 template<typename

[bzoj1911][Apio2010特别行动队]

Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT Solution 斜率优化动态规划 首先易得出这样的一个朴素状态转移方程 f[i]=max{f[j]+cal(sum[i]-sum[j])} 其中j<i,且cal(x)=a*x*x+b*x+c 那么设转移方程中的式子为V 若i<j,且V(j)>V(i) 那么,f[j]-f[i]+a*sum[j]^2-a*sum[i]^2+b*(su

hdu3507 Print Article[斜率优化dp入门题]

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 11761    Accepted Submission(s): 3586 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antiqu

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\) \(

【BZOJ1911】[Apio2010]特别行动队 斜率优化DP

想了好久啊.... 用了我感觉比较好写的一种(因为没写过维护凸包),另一种是维护凸包的做法,本质一样?推荐http://www.mamicode.com/info-detail-345781.html. 网上的大多数解法: DP:f[i]=max(f[j]+a*(sum[i]-sum[j])^2+b(sum[i]-sum[j])+c) 显然复杂度不对. 那么假设j>k且f[j]优于f[k] f[j]-f[k]+a*(sum[j]^2-sum[k]^2)-b*(sum[j]-sum[k])>2*

【BZOJ-1911】特别行动队 DP + 斜率优化

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3478  Solved: 1586[Submit][Status][Discuss] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT Source Solution 题意非常明显,将n个数划分成多段区间,使得总价值最大,每段区间的价值为$powersu