HDU 3045 (斜率优化)
2016-06-25 21:49
246 查看
题目链接:点击这里
题意:n个数,分成若干块,每一块的数量不能小于k,每一块的花费是所有的数减去块中最小值的和。每一块和的最小值。
显然要排序以后分块,设fi表示(1,i)分块后的最小和,那么有fi=min{fj+sumi−sumj−aj+1∗(i−j)∥∥i−j≥k}
假设j比k更优(k≤j)fj+sumi−sumj−aj+1×(i−j)≤fk+sumi−sumk−ak+1×(i−k)
整理一下就是斜率式子了fj+j×aj+1−sumj−fk−k×ak+1+sumkaj+1−ak+1≤i
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define maxn 400005 long long dp[maxn]; int n, k, que[maxn]; long long a[maxn], sum[maxn]; long long scan () { char ch=' '; while(ch<'0'||ch>'9')ch=getchar(); long long x=0; while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); return x; } long long up (int i, int j) { return dp[i]+1LL*i*a[i+1]-sum[i] - (dp[j]+1LL*j*a[j+1]-sum[j]); } long long down (int i, int j) { return a[i+1]-a[j+1]; } int main () { while (scanf ("%d%d", &n, &k) == 2) { sum[0] = 0; for (int i = 1; i <= n; i++) a[i] = scan ();; sort (a+1, a+1+n); for (int i = 1; i <= n; i++) sum[i] = sum[i-1]+a[i]; dp[0] = 0; for (int i = 1; i < k*2 && i <= n; i++) { dp[i] = sum[i] - 1LL*i*a[1]; } int L = 0, R = 0; que[R++] = 0; que[R++] = k; for (int i = 2*k; i <= n; i++) { while (L+1 < R && up (que[L+1], que[L]) <= 1LL*i*down (que[L+1], que[L])) L++; int j = que[L]; dp[i] = dp[j] + sum[i]-sum[j]-a[j+1]*(i-j); while (L+1 < R && up (i-k+1, que[R-1])*down (que[R-1], que[R-2]) <= up (que[R-1], que[R-2])*down (i-k+1, que[R-1])) R--; que[R++] = i-k+1; } printf ("%lld\n", dp ); } return 0; }
相关文章推荐
- LoaderManager访问SD里面的数据库
- 判断是否为回文数
- 那点代码, 谁都会写!------以后我会在博客中多加入一些思路方面的东东, 少写一些实际的代码
- (第5讲)单链表(带头结点和不带头结点)
- 两个日期差值
- linux下C/C++头文件梳理,看完这篇再也不会搞糊涂头文件了!
- 210. Course Schedule II
- bzoj2698: 染色
- 使用注解标注Servlet
- Android_GET与POST_面向过程
- hdu4882ZCC Loves Codefires【贪心】2014多校联合
- 图书管理系统JAVA语言
- 正则表达式
- 随机行读取文件
- OJ网站小结
- substr,substring,slice 的区别
- Freezer - OpenStack备份项目简介
- 通过异步任务LoaderManager加载Cursor游标
- 目标跟踪算法的分类(二)
- 自制编译器---c++实现词法分析器