一类斜率优化的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)$和 ...
 
随机推荐
- QNX 多线程 (线程1每隔20ms读取 number;线程2每隔10ms计算一次)
			
#include <pthread.h>#include <stdio.h>#include <sys/time.h>#include <string.h&g ...
 - 用MFC实现WebGUI--(CDHtmlDialog)
			
自从去年年底一次棘手的界面,开始研究用web做界面到现在大约1年,这一年间不是局限在实现层面,也并非一直研究这一个问题,有很多问题其实不是问题,只是自己没有想清楚或者思想没放开.对于一个界面开发人员, ...
 - 怎么提高ArcGIS for Desktop10.x的性能
			
Esri新公布了一篇提高ArcGIS for Desktop10.x的性能的文章.大家能够关注一下 http://support.esri.com/en/knowledgebase/techartic ...
 - 网络编程API-上 (基本API)
			
htons.ntohs.htonl和ntohl函数 Linux提供了4个函数来完毕主机字节序和网络字节序之间的转换 #include <netinet/in.h> uint16_t hto ...
 - openwrt 3g模块上网
			
硬件环境: 开发板为RT5053F 3G模块为中兴 MC2176 电信版 以下是操作步骤 加入VID .PID VID . PID 的获取方法是 将设备插入电脑在linux下执行 ...
 - js动态添加Div
			
利用JavaScript动态添加Div的方式有很多,在这次开发中有用到,就搜集了一下比较常用的. 一.在一个Div前添加Div <html> <body> <div id ...
 - JavaFX2: 鼠标拖动选择和Ctrl+Shift连续区间选择的ListView
			
JavaFX2的ListView中的多选没有提供鼠标拖动选择的功能,同时按下Ctrl和Shift后连续的区间选中也不支持,以下代码用于处理这两个问题,细节见代码注释: import com.sun.j ...
 - SQL SERVER CHARINDEX函数
			
CHARINDEX函数经常常使用来在一段字符中搜索字符或者字符串.假设被搜索的字符中包括有要搜索的字符,那么这个函数返回一个非零的整数,这个整数是要搜索的字符在被搜索的字符中的開始位数.即CHARIN ...
 - Jobbox.io(职位盒子): 新兴的面向技术人才的职场招聘众推平台
			
人才招聘市场一个主要问题在于猎头中介费昂贵.这对于大公司而言,或可接受. 但对于海量小微企业而言招聘成本和效率之间的平衡是非常大的一个问题. 现在产品猎场(Product Hunt)上出现了一些新的招 ...
 - linux下的开源移动图像监测程序--motion编译与配置
			
前几天在网上偶然看到一篇博客,是利用linxu下的开源的motion搭建嵌入式视频动态监控系统,感觉很好很强大于,是就想自己编译移植一下试试. 所谓移动图像监测,简单来说就是利用摄像头定点监测某个区域 ...