一类斜率优化的dp(特有性质:只能连续,不能交叉)
给定一个有n个数的集合,将这个集合分成m个子集,要求子集的并等于全集
求花费最小。
花费为该子集的(最大数-最小数)的平方。
我们将n个数排序,
a < b < c < d
那么不可能a,c一个集合,b,c一个集合
明显a,b一个集合,c,d一个集合更优
也就是说某一个数只能和它前面的连续几个数合起来形成一个子集。 正是因为有这个性质才能dp
dp[i][j]表示第j个数在第i个集合的最小花费
dp[i][j] = min(dp[i][j],dp[i-1][k]) 1<=k<j
dp[i-1][k1] + (a[j]-a[k1+1])^2 < dp[i-1][k2]+(a[j]-a[k2+1])^2
dp[i-1][k1]+a[k1]^2-(dp[i-1][k2]+a[k2]^2) < 2a[j]*(a[k1+1]-a[k2+1])
这样就能够用斜率优化了,由于是求最小值,所以维护一个下凸包就行了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef int LL;
const int INF = <<;
/*
给定一个有n个数的集合,将这个集合分成m个子集,要求子集的并等于全集
求花费最小, 花费为什么每个集合的(最大值-最小值)的平方 dp[i][j]表示第j个数在第i个集合的最小花费
用滚动数组压缩空间
*/ const int N = + ;
const int M = + ;
LL a[N];
LL dp[][N];
int q[N], head, tail;
LL dw(LL a, LL b)
{
return (a - b)*(a - b);
}
LL getUp(int k1, int k2, int c)
{
return dp[c][k1] + a[k1 + ] * a[k1 + ] - (dp[c][k2] + a[k2 + ] * a[k2 + ]);
}
LL getDown(int k1, int k2)
{
return * (a[k1 + ] - a[k2 + ]);
}
int main()
{
int t, n, m;
scanf("%d", &t);
for (int k = ; k <= t; ++k)
{
scanf("%d%d", &n, &m);
for (int i = ; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + , a + n + );
n = unique(a + , a + n + ) - a - ;
if (m > n)
m = n;
int c = ;
for (int j = ; j <= n; ++j)
dp[][j] = dw(a[j], a[]);
for (int i = ; i <= m; ++i)
{
head = tail = ;
for (int j = i; j <= n; ++j)
{
while (head + < tail && getUp(j - , q[tail - ], c)*getDown(q[tail - ], q[tail - ])
<= getUp(q[tail - ], q[tail - ], c)*getDown(j - , q[tail - ]))
tail--;
q[tail++] = j - ;
while (head + < tail&&getUp(q[head + ], q[head], c) < a[j] * getDown(q[head+], q[head]))
head++;
dp[c ^ ][j] = dp[c][q[head]] + dw(a[j], a[q[head] + ]);
}
c ^= ;
}
printf("Case %d: %d\n",k, dp[c][n]);
}
return ;
}
n头牛,分成几组,每组至少有k头牛
要求费用最小,
费用是每组所有牛的moo,减去该组中最小的moo
将moo排序
那么如果是分成两组的话,那么不可能是a,c一组, b,d一组
a,b,一组比c,d一组肯定更优。
又遇到了有这种性质的题目, 连续比交叉更优,这样,才能用dp来解决,
dp[j]表示以j结尾的team的最小花费
(dp[k1]-sum[k1]+k1*moo[k1+1]) - (dp[k2]-sum[k2]+k2*moo[k2+1]) < i*(moo[k1+1]-moo[k2+1])
dp[k1]+k1*moo[k1+1] - (dp[k2]+k2*moo[k2+1]) < i * (moo[k1+1]-moo[k2+1])
所以维护递增的斜率
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef __int64 LL;
const int INF = <<;
/*
n头牛,分成几组,每组至少有k头牛
要求费用最小,
费用是每组所有牛的moo,减去该组中最小的moo
a < b < c < d
那么如果是分成两组的话,那么不可能是a,c一组, b,d一组
a,b,一组比c,d一组肯定更优。
又遇到了有这种性质的题目, 连续比交叉更优,这样,才能用dp来解决,
dp[j]表示以j结尾的team的最小花费
(dp[k1]-sum[k1]+k1*moo[k1+1]) - (dp[k2]-sum[k2]+k2*moo[k2+1]) < i*(moo[k1+1]-moo[k2+1])
dp[k1]+k1*moo[k1+1] - (dp[k2]+k2*moo[k2+1]) < i * (moo[k1+1]-moo[k2+1])
所以维护递增的斜率 */
const int N = + ;
LL moo[N], dp[N], sum[N];
int q[N], head, tail; LL getUp(int k1, int k2)
{
return dp[k1] + k1*moo[k1 + ] - sum[k1] - (dp[k2] + k2*moo[k2 + ] - sum[k2]);
}
LL getDown(int k1, int k2)
{
return moo[k1 + ] - moo[k2 + ];
}
int main()
{
int n, t;
while (scanf("%d%d", &n, &t) != EOF)
{
for (int i = ; i <= n; ++i)
{
scanf("%I64d", &moo[i]);
}
sort(moo + , moo + n + );
for (int i = ; i <= n; ++i)
sum[i] = moo[i] + sum[i - ];
for (int i = t; i <= n; ++i)
dp[i] = sum[i] - i*moo[]; head = tail = ;
q[tail++] = ;
q[tail++] = t;
int k = t + ;
for (int i = *t; i <= n; ++i)
{
while (head + < tail&&getUp(q[head + ], q[head]) < i*getDown(q[head + ], q[head]))
head++;
dp[i] = dp[q[head]] + sum[i]-sum[q[head]] - (i-q[head])*moo[q[head] + ];
while (head + < tail&&getUp(k, q[tail - ])*getDown(q[tail - ], q[tail - ]) <= getUp(q[tail - ], q[tail - ])*getDown(k, q[tail - ]))
tail--;
q[tail++] = k++;
}
printf("%I64d\n", dp[n]);
}
return ;
}
一类斜率优化的dp(特有性质:只能连续,不能交叉)的更多相关文章
- 队列优化和斜率优化的dp
可以用队列优化或斜率优化的dp这一类的问题为 1D/1D一类问题 即状态数是O(n),决策数也是O(n) 单调队列优化 我们来看这样一个问题:一个含有n项的数列(n<=2000000),求出每一 ...
- [NOI2014]购票 --- 斜率优化 + 树形DP + 数据结构
[NOI2014]购票 题目描述 今年夏天,NOI在SZ市迎来了她30周岁的生日. 来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每 ...
- Luogu P5468 [NOI2019]回家路线 (斜率优化、DP)
题目链接: (luogu) https://www.luogu.org/problemnew/show/P5468 题解: 爆long long毁一生 我太菜了,这题这么简单考场上居然没想到正解-- ...
- [bzoj 2726] 任务安排 (斜率优化 线性dp)
3月14日第三题!!!(虽然是15号发的qwq) Description 机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3-N.这N个任务被分成若干批 ...
- 斜率优化DP讲解
对于斜率优化的DP转移方程,一般以w[i]=max(w[j]+(sum[i]-sum[j])*v)的1D1D形式为主,直观看来就是前j个为若干个阶段,第j+1到第i个为一个阶段,每个阶段有自己的代价或 ...
- 【BZOJ-1597】土地购买 DP + 斜率优化
1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2931 Solved: 1091[Submit] ...
- [HNOI2008]玩具装箱TOY --- DP + 斜率优化 / 决策单调性
[HNOI2008]玩具装箱TOY 题目描述: P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京. 他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器 ...
- DP玄学优化——斜率优化
--以此博客来悼念我在\(QBXT\)懵逼的时光 \(rqy\; tql\) (日常%\(rqy\)) 概念及用途 斜率优化是\(DP\)的一种较为常用的优化(据说在高中课本里稍有提及),它可以用于优 ...
- DP斜率优化学习笔记
斜率优化 首先,可以进行斜率优化的DP方程式一般式为$dp[i]=\max_{j=1}^{i-1}/\min_{j=1}^{i-1}\{a(i)*x(j)+b(i)*y(j)\}$ 其中$a(j)$和 ...
随机推荐
- 使用ServletFileUpload实现上传
1.首先我们应该为上传的文件建一个存放的位置,一般位置分为暂时和真是目录,那我们就须要获取这俩个目录的绝对路径,在servlet中我们能够这样做 ServletContext application ...
- 细说在兄弟连搞上PHP的那些事儿
(据说大家都是这么开头的)又到6月份了,想想自己毕业已经整整一年时间了,这一年可能会是我一生中印象最最深刻的一年,从满怀希望地踏入社会到自信满满 地开始第一份工作再到2个多月后又灰溜溜地辞去工作,回到 ...
- (step4.3.9)hdu 1584(蜘蛛牌——DFS)
题目大意:本体是中文题,可以直接在OJ上看 /* * 1584_2.cpp * * Created on: 2013年8月22日 * Author: Administrator */ #include ...
- SINGLETON(单例模式)---(孤独的人)
很多时候,我们都很彷徨,因为,在身边的朋友,很少. package patterns.createable.singleton; /** * 孤独的人啊 * 我为你写了一个类 * 这个类,在我们的程序 ...
- DLNA_百度百科
DLNA_百度百科 DLNA
- SQL视图索引
视图: 视图就相当于一个查询结果,它相对应的是表 表----真正存储数据的地方 视图---不存储数据,展示查询的结果 注意: 1.视图就是为了查询数据方便.一般不要试图向视图中插入数据,容易出错. 2 ...
- Iron Foundry
Iron Foundry Provided by Tier 3 Iron Foundry is a project initiated by the engineers of Tier 3, an e ...
- VSTO学习笔记(二)Excel对象模型
原文:VSTO学习笔记(二)Excel对象模型 上一次主要学习了VSTO的发展历史及其历代版本的新特性,概述了VSTO对开发人员的帮助和效率提升.从这次开始,将从VSTO 4.0开始,逐一探讨VSTO ...
- HDU 4643 GSM 简单计算几何
今天比赛的时候略坑, admin告诉我询问Q的个数不超过n^2, 赛后敲了个 O(Q*m^3)的复杂度,但这个复杂度常数比较低,可能在除以个小常数, 300ms过了,真心无语,数据应该水了吧,比赛的时 ...
- (step 8.2.13)hdu 1524(A Chess Game)
题目大意 : 在一个 有向无环图顶点上面有几个棋子, 2个人轮流操作, 每次操作就是找一个棋子往它能够移 动的地方移动一格, 不能操作的人输. 输入第一行 为一个 N , 表示有 N 个顶点 0 -& ...