HDU3045 Picnic Cows —— 斜率优化DP
题目链接:https://vjudge.net/problem/HDU-3045
Picnic Cows
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3491 Accepted Submission(s): 1124
Farmer Carolina takes her N (1<N≤400000) cows to the destination, but she finds every cow’s degree of interest in this activity is so different that they all loss their interests. So she has to group them to different teams to make sure that every cow can go to a satisfied team. Considering about the security, she demands that there must be no less than T(1<T≤N)cows in every team. As every cow has its own interest degree of this picnic, we measure this interest degree’s unit as “Moo~”. Cows in the same team should reduce their Moo~ to the one who has the lowest Moo~ in this team——It’s not a democratical action! So Carolina wishes to minimize the TOTAL reduced Moo~s and groups N cows into several teams.
For example, Carolina has 7 cows to picnic and their Moo~ are ‘8 5 6 2 1 7 6’ and at least 3 cows in every team. So the best solution is that cow No.2,4,5 in a team (reduce (2-1)+(5-1) Moo~)and cow No.1,3,6,7 in a team (reduce ((7-6)+(8-6)) Moo~),the answer is 8.
For each test case, the first line has two integer N, T indicates the number of cows and amount of Safe-base line.
Following n numbers, describe the Moo~ of N cows , 1st is cow 1 , 2nd is cow 2, and so on.
8 5 6 2 1 7 6
题意:
有n头牛去野营,烧烤,吃什么,牛肉?细思极恐。不扯了。将这n头牛分成若干组,且每一组至少要有T头。每头牛都有一个值,一个组的值是这个组内,所有牛的值减去最小值的差之和。而总和为所有组的值之和,问:怎样分配,才能使得总和最小?
题解:
1.可得一个结论:尽量把值相近的牛分到同一组。所以首先需要根据值的大小对牛进行排序。然后就是一个区间划分的问题了。
2.由于n<=4e5,O(n^2)DP枚举是会超时的,所以需要利用斜率进行优化。
3.由于题目规定了每一组的个数必须大于等于T,因此需要特别处理:
1) dp值从下标为T开始求,因为1~T-1都不能构成一组,其DP没有意义。
2) 在求得dp[i]之后,不能直接把 i 放进队列中,因为 i 不一定能为i+1、i+2……等作状态转移,因为必须要满足一组个数大于等于T的要求。然而,这个还不是最重要的,如果直接把 i 放进队列,那么因为斜率优化所进行的操作:把认为比 i 劣且在队列里的元素出队了,而这些元素又是往后的状态所必须知道的。因此就出现了错误。
3) 根据2) 我们需要限定:在队列里的元素,必须都是往后状态所能够转移的,相比之下只是优劣问题而已。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int MAXM = 1e5+;
const int MAXN = 4e5+; LL val[MAXN], sum[MAXN], dp[MAXN];
int q[MAXN], head, tail; LL getUp(int j, int k)
{
return (dp[j]-sum[j]) - (dp[k]-sum[k]);
} LL getDown(int j, int k)
{
return j-k;
} LL getDp(int i, int j)
{
return dp[j]+(sum[i]-sum[j])-1LL*(i-j)*val[i];
} int main()
{
int T, n;
while(scanf("%d%d", &n,&T)!=EOF)
{
for(int i = ; i<=n; i++)
scanf("%lld", &val[i]);
sort(val+, val++n);
reverse(val+, val++n); //降序 sum[] = ;
for(int i = ; i<=n; i++)
sum[i] = sum[i-]+val[i]; // O(n^2)的写法:
// for(int i = T; i<=n; i++)
// {
// dp[i] = sum[i]-i*val[i];
// for(int j = T; j<=i-T; j++)
// dp[i] = min(dp[i], dp[j]+sum[i]-sum[j]-1LL*(i-j)*val[i]);
// } head = tail = ;
dp[] = ;
q[tail++] = ;
for(int i = T; i<=n; i++) //从T开始,因为前面的都无效
{
while(head+<tail && getUp(q[head+],q[head])<=
-1LL*getDown(q[head+],q[head])*val[i]) head++;
dp[i] = getDp(i, q[head]); int j = i-T+; //加入对从下一个开始有效的状态,而i-T+1对i+1、i+2……有效
if(j<T) continue; //只有j>=T, j才有效,能转移状态
while(head+<tail && 1LL*getUp(j, q[tail-])*getDown(q[tail-],q[tail-])<=
1LL*getUp(q[tail-],q[tail-])*getDown(j, q[tail-])) tail--;
q[tail++] = j;
}
printf("%I64d\n", dp[n]);
}
}
错误写法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int MAXM = 1e5+;
const int MAXN = 1e3+; int val[MAXN], sum[MAXN], dp[MAXN];
int q[MAXN], head, tail; int getUp(int i, int j)
{
return dp[i] - dp[j];
} int getDown(int i, int j)
{
return sum[i] - sum[j];
} int getDp(int i, int j)
{
return dp[j] + (sum[i]-sum[j]+)*val[i];
} int main()
{
int T, n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
sum[] = ;
for(int i = ; i<=n; i++)
scanf("%d%d", &sum[i],&val[i]), sum[i] += sum[i-]; dp[] = ;
head = tail = ;
q[tail++] = ;
for(int i = ; i<=n; i++)
{
while(head+<tail && getUp(q[head+],q[head])<=getDown(q[head+],q[head])*val[i]) head++;
dp[i] = getDp(i, q[head]);
/*
直接把i加进去为何错误?因为i的存在不能为i+1的转移作贡献,本来放着没什么关系的,
关键是i加进去的时候,还可能会把前面的去掉,这样就有可能把能为i+1转移的去掉了。
所以,加进队列的应该是那些能为往后所有状态转移的。
*/
while(head+<tail && getUp(i, q[tail-])*getDown(q[tail-],q[tail-])<=
getUp(q[tail-],q[tail-])*getDown(i, q[tail-])) tail--;
q[tail++] = i;
}
printf("%d\n", dp[n]);
}
}
HDU3045 Picnic Cows —— 斜率优化DP的更多相关文章
- hdu 3045 Picnic Cows(斜率优化DP)
题目链接:hdu 3045 Picnic Cows 题意: 有n个奶牛分别有对应的兴趣值,现在对奶牛分组,每组成员不少于t, 在每组中所有的成员兴趣值要减少到一致,问总共最少需要减少的兴趣值是多少. ...
- HDU 3045 Picnic Cows(斜率优化DP)
Picnic Cows Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- POJ2018 Best Cow Fences —— 斜率优化DP
题目链接:https://vjudge.net/problem/POJ-2018 Best Cow Fences Time Limit: 1000MS Memory Limit: 30000K T ...
- 【转】斜率优化DP和四边形不等式优化DP整理
(自己的理解:首先考虑单调队列,不行时考虑斜率,再不行就考虑不等式什么的东西) 当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环 (一重 ...
- bzoj-4518 4518: [Sdoi2016]征途(斜率优化dp)
题目链接: 4518: [Sdoi2016]征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地 ...
- bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)
题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...
- [BZOJ3156]防御准备(斜率优化DP)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3156 分析: 简单的斜率优化DP
- 【BZOJ-1096】仓库建设 斜率优化DP
1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3719 Solved: 1633[Submit][Stat ...
- BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP
1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再 ...
随机推荐
- android中自定义下拉框(转)
android自带的下拉框好用不?我觉得有时候好用,有时候难有,项目规定这样的效果,自带的控件实现不了,那么只有我们自己来老老实实滴写一个新的了,其实最基本的下拉框就像一些资料填写时,点击的时候出现在 ...
- Codeforces 486D Valid Sets (树型DP)
题目链接 Valid Sets 题目要求我们在一棵树上计符合条件的连通块的个数. 满足该连通块内,点的权值极差小于等于d 树的点数满足 n <= 2000 首先我们先不管这个限制条件,也就是先考 ...
- STM32调试问题
1.JLINK V8 error:flash download failed - could not load file: Options for Target 'Targer 1'下的菜单下Outp ...
- 集成CCFlow工作流与GPM的办公系统驰骋CCOA介绍(三)
通过组织结构能够对项目的岗位.部门.人员进行增删改操作. 加入新部门.并为新部门加入人员: 选中部门后,点击鼠标右键,能够选择加入平级部门或下属部门. 新建部门时,须要给部门设置部门编号.名称.与部门 ...
- 【LeetCode-面试算法经典-Java实现】【010-Regular Expresssion Matching(正則表達式匹配)】
[010-Regular Expresssion Matching(正則表達式匹配)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Implement regular ...
- 增强版的RecycleViewAdapter,能够直接使用
在Android的项目中.须要大量的列表组件来显示数据.在之前的项目中一直使用的是ListView 组件,可是在最新的V7包中出现了能后替代ListView的组件RecycleView. 所以在新的项 ...
- CF 568A(Primes or Palindromes?-暴力推断)
A. Primes or Palindromes? time limit per test 3 seconds memory limit per test 256 megabytes input st ...
- PHP中的多行字符串传递给JavaScript方法两则
PHP和JavaScript都是初学.近期有这么个需求: 例如说有一个PHP的多行字符串: $a = <<<EOF thy38 csdn blog EOF; 传递给JavaScrip ...
- Java 兔子问题(斐波那契数列)扩展篇
Java兔子问题(斐波那契数列)扩展篇 斐波那契数列指的是这样一个数列 0, 1, 1, 2,3, 5, 8, 13, 21, 34, 55, 89, 144, ...对于这个数列仅仅能说将兔子生产周 ...
- ViewPagerIndicator 取代TabHost,实现滑动tab,引导页等效果
https://github.com/eltld/ViewPagerIndicator 取代TabHost,实现滑动tab,引导页等效果