hdu3045之斜率DP

Picnic Cows

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1563    Accepted Submission(s): 478

Problem Description

It’s summer vocation now. After tedious milking, cows are tired and wish to take a holiday. So Farmer Carolina considers having a picnic beside the river. But there is a problem, not all the cows consider it’s a good idea! Some cows like to swim in West Lake,
some prefer to have a dinner in Shangri-la ,and others want to do something different. But in order to manage expediently, Carolina coerces all cows to have a picnic!

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.

Input

The input contains multiple cases.

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.

Output

One line for each test case, containing one integer means the minimum of the TOTAL reduced Moo~s to group N cows to several teams.

Sample Input

7 3
8 5 6 2 1 7 6

Sample Output

8
/*题意:
有n个奶牛分别有对应的兴趣值,现在对奶牛分组,每组成员不少于t,
在每组中所有的成员兴趣值要减少到一致,问总共最少需要减少的兴趣值是多少。

分析:
先对n个数进行排序,则可以分析出分组成员一定是连续的
dp[i]表示前i个数得到的最少值
则:从j~i作为一组
dp[i]=dp[j-1]+sum[i]-sum[j-1]-(i-j+1)*s[j];//sum[i]表示前i个数的和
=>dp[i]=dp[j-1]+sum[i]-sum[j-1]+(j-1)*s[j]-i*s[j];
由于有i*s[j]这一项,所以无法直接在扫描数组的过程中用单调队列维护:
dp[j-1]-sum[j-1]+(j-1)*s[j]-i*s[j]的最小值。
考虑用斜率dp!
假定k<j<=i-t以j~i作为一组比以k~i作为一组更优
则:
dp[j-1]+sum[i]-sum[j-1]-(i-j+1)*s[j] <= dp[k-1]+sum[i]-sum[k-1]-(i-k+1)*s[k]
=>dp[j-1]+sum[i]-sum[j-1]+(j-1)*s[j]-i*s[j] <= dp[k-1]+sum[i]-sum[k-1]+(k-1)*s[k]-i*s[k]
=>(dp[j-1]-sum[j-1]+(j-1)*s[j] - (dp[k-1]-sum[k-1]+(k-1)*s[k]))/(s[j]-s[k])<=i;//保证s[j]>=s[k]
令:
y1 = dp[j-1]-sum[j-1]+(j-1)*s[j]
y2 = dp[k-1]-sum[k-1]+(k-1)*s[k]
x1 = s[j]
x2 = s[k]
所以变成了:
(y1 - y2)/(x1 - x2) <= i;
斜率!
只需要维护这个斜率即可
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef __int64 LL;
using namespace std;

const int MAX = 400000 + 10;
int n,t,q[MAX];
LL s[MAX],sum[MAX],dp[MAX];

LL GetY(int j,int k){
	return dp[j-1]-sum[j-1]+(j-1)*s[j]-(dp[k-1]-sum[k-1]+(k-1)*s[k]);
}

LL GetX(int j,int k){
	return s[j]-s[k];
}

LL DP(){
	int head=0,tail=1;
	q[0]=1;
	for(int i=1;i<=n;++i)sum[i]=sum[i-1]+s[i];
	for(int i=t;i<2*t;++i)dp[i]=sum[i]-i*s[1];//初始化
	for(int i=2*t;i<=n;++i){//i从2*t开始
		while(head+1<tail && GetY(i-t+1,q[tail-1])*GetX(q[tail-1],q[tail-2])<=GetY(q[tail-1],q[tail-2])*GetX(i-t+1,q[tail-1]))--tail;
		q[tail++]=i-t+1;
		while(head+1<tail && GetY(q[head+1],q[head])<=GetX(q[head+1],q[head])*i)++head;
		dp[i]=dp[q[head]-1]+sum[i]-sum[q[head]-1]+(q[head]-1)*s[q[head]]-i*s[q[head]];
	}
	return dp[n];
}

int main(){
	while(~scanf("%d%d",&n,&t)){
		for(int i=1;i<=n;++i)scanf("%I64d",s+i);//cin>>s[i];
		sort(s+1,s+1+n);
		printf("%I64d\n",DP());
	}
	return 0;
}
/*题意:
有n个奶牛分别有对应的兴趣值,现在对奶牛分组,每组成员不少于t,
在每组中所有的成员兴趣值要减少到一致,问总共最少需要减少的兴趣值是多少。

分析:
先对n个数进行排序,则可以分析出分组成员一定是连续的
dp[i]表示前i个数得到的最少值
则:从j+1~i作为一组
dp[i]=dp[j]+sum[i]-sum[j]-(i-j)*s[j+1];//sum[i]表示前i个数的和
=>dp[i]=dp[j]+sum[i]-sum[j]+j*s[j+1]-i*s[j+1];
由于有i*s[j+1]这一项,所以无法直接在扫描数组的过程中用单调队列维护:
dp[j]-sum[j]+j*s[j+1]-i*s[j+1]的最小值。
考虑用斜率dp!
假定k<=j<i-t以j+1~i作为一组比以k+1~i作为一组更优
则:
dp[j]+sum[i]-sum[j]-(i-j)*s[j+1] <= dp[k]+sum[i]-sum[k]-(i-k)*s[k+1]
=>dp[j]+sum[i]-sum[j]+j*s[j+1]-i*s[j+1] <= dp[k]+sum[i]-sum[k]+k*s[k+1]-i*s[k+1]
=>(dp[j]-sum[j]+j*s[j+1] - (dp[k]-sum[k]+k*s[k+1]))/(s[j+1]-s[k+1])<=i;//保证s[j]>=s[k]
令:
y1 = dp[j]-sum[j]+j*s[j+1]
y2 = dp[k]-sum[k]+k*s[k+1]
x1 = s[j+1]
x2 = s[k+1]
所以变成了:
(y1 - y2)/(x1 - x2) <= i;
斜率!
只需要维护这个斜率即可
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef __int64 LL;
using namespace std;

const int MAX = 400000 + 10;
int n,t,q[MAX];
LL s[MAX],sum[MAX],dp[MAX];

LL GetY(int j,int k){
	return dp[j]-sum[j]+j*s[j+1]-(dp[k]-sum[k]+k*s[k+1]);
}

LL GetX(int j,int k){
	return s[j+1]-s[k+1];
}

LL DP(){
	int head=0,tail=1;
	q[0]=0;
	for(int i=1;i<=n;++i)sum[i]=sum[i-1]+s[i];
	for(int i=t;i<2*t;++i)dp[i]=sum[i]-i*s[1];//初始化
	for(int i=2*t;i<=n;++i){//i从2*t开始
		int j=i-t;
		while(head+1<tail && GetY(j,q[tail-1])*GetX(q[tail-1],q[tail-2])<=GetY(q[tail-1],q[tail-2])*GetX(j,q[tail-1]))--tail;
		q[tail++]=j;
		while(head+1<tail && GetY(q[head+1],q[head])<=GetX(q[head+1],q[head])*i)++head;
		dp[i]=dp[q[head]]+sum[i]-sum[q[head]]+q[head]*s[q[head]+1]-i*s[q[head]+1];
	}
	return dp[n];
}

int main(){
	while(~scanf("%d%d",&n,&t)){
		for(int i=1;i<=n;++i)scanf("%I64d",s+i);//cin>>s[i];
		sort(s+1,s+1+n);
		printf("%I64d\n",DP());
	}
	return 0;
}
/*题意:
有n个奶牛分别有对应的兴趣值,现在对奶牛分组,每组成员不少于t,
在每组中所有的成员兴趣值要减少到一致,问总共最少需要减少的兴趣值是多少。

分析:
先对n个数进行排序,则可以分析出分组成员一定是连续的
dp[i]表示前i个数得到的最少值
则:从j+1~i作为一组
dp[i]=dp[j]+sum[i]-sum[j]-(i-j)*s[j+1];//sum[i]表示前i个数的和
=>dp[i]=dp[j]+sum[i]-sum[j]+j*s[j+1]-i*s[j+1];
由于有i*s[j+1]这一项,所以无法直接在扫描数组的过程中用单调队列维护:
dp[j]-sum[j]+j*s[j+1]-i*s[j+1]的最小值。
考虑用斜率dp!
假定k<=j<i-t以j+1~i作为一组比以k+1~i作为一组更优
则:
dp[j]+sum[i]-sum[j]-(i-j)*s[j+1] <= dp[k]+sum[i]-sum[k]-(i-k)*s[k+1]
=>dp[j]+sum[i]-sum[j]+j*s[j+1]-i*s[j+1] <= dp[k]+sum[i]-sum[k]+k*s[k+1]-i*s[k+1]
=>(dp[j]-sum[j]+j*s[j+1] - (dp[k]-sum[k]+k*s[k+1]))/(s[j+1]-s[k+1])<=i;//保证s[j]>=s[k]
令:
y1 = dp[j]-sum[j]+j*s[j+1]
y2 = dp[k]-sum[k]+k*s[k+1]
x1 = s[j+1]
x2 = s[k+1]
所以变成了:
(y1 - y2)/(x1 - x2) <= i;
斜率!
只需要维护这个斜率即可
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef __int64 LL;
using namespace std;

const int MAX = 400000 + 10;
int n,t,q[MAX];
LL s[MAX],sum[MAX],dp[MAX];

LL GetY(int j,int k){
    return dp[j]-sum[j]+j*s[j+1]-(dp[k]-sum[k]+k*s[k+1]);
}

LL GetX(int j,int k){
    return s[j+1]-s[k+1];
}

LL DP(){
    int head=0,tail=1;
    q[0]=0;
    for(int i=1;i<=n;++i)sum[i]=sum[i-1]+s[i];
    //for(int i=t;i<2*t;++i)dp[i]=sum[i]-i*s[1];//初始化
    for(int i=1;i<=n;++i){//i从2*t开始
        while(head+1<tail && GetY(q[head+1],q[head])<=GetX(q[head+1],q[head])*i)++head;
        dp[i]=dp[q[head]]+sum[i]-sum[q[head]]+q[head]*s[q[head]+1]-i*s[q[head]+1];
        if(i-t+1<t)continue;
        while(head+1<tail && GetY(i-t+1,q[tail-1])*GetX(q[tail-1],q[tail-2])<=GetY(q[tail-1],q[tail-2])*GetX(i-t+1,q[tail-1]))--tail;
        q[tail++]=i-t+1;
    }
    return dp[n];
}

int main(){
    while(~scanf("%d%d",&n,&t)){
        for(int i=1;i<=n;++i)scanf("%I64d",s+i);//cin>>s[i];
        sort(s+1,s+1+n);
        printf("%I64d\n",DP());
    }
    return 0;
}

hdu3045之斜率DP

时间: 2024-10-13 04:11:57

hdu3045之斜率DP的相关文章

bzoj 1597 斜率DP

1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5115  Solved: 1897[Submit][Status][Discuss] Description 农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地

bzoj 1492 [NOI2007]货币兑换Cash(斜率dp+cdq分治)

Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目.答案保留3 位小数. Sample Input 3 100 1 1 1 1 2 2 2 2 3 Sample Output 225.000 HINT 测试数据设计使得精度误差不会超过10-7.对于40%的测试数据,满足N

hdu3669之二维斜率DP

Cross the Wall Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 4176    Accepted Submission(s): 748 Problem Description "Across the Great Wall, we can reach every corner in the world!" No

HNOI2008 玩具装箱toy (BZOJ1010,斜率dp)

传送门 1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MB Description P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维 容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的. 同时如果一个一维容器中有多个玩具,那么两件玩

bzoj 3156 防御准备(斜率DP)

3156: 防御准备 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 837  Solved: 395[Submit][Status][Discuss] Description Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小的战线花费值. Sample Input 10 2 3 1 5 4 5 6 3 1 2 Sample Output 18 HIN

[DP优化方法之斜率DP]

什么是斜率dp呢 大概就把一些单调的分组问题 从O(N^2)降到O(N) 具体的话我就不多说了 看论文: http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html 我自己也补充几句: 其实斜率dp有很多种打法 有凸包 有截距 有直接比较斜率的 因为我比较弱 所以的话就学最弱智的比较斜率的 听wph说截距很好理解 然后的话 讲课的时候scy说什么要证单调性什么鬼的 我在学的过程中好像没遇到就不管了 虽然我很弱 反正我能AC就行了

斜率dp cdq 分治

f[i] = min { f[j] + sqr(a[i] - a[j]) } f[i]= min { -2 * a[i] * a[j] + a[j] * a[j] + f[j] } + a[i] * a[i] 由于a[i]不是单调递增的,不能直接斜率dp. 考虑有cdq分治来做,复杂度(nlog2n) 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm&

hdu 3507 斜率dp

不好理解,先多做几个再看 此题是很基础的斜率DP的入门题. 题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M 让我们求这个费用的最小值. 设dp[i]表示输出前i个的最小费用,那么有如下的DP方程: dp[i]= min{ dp[j]+(sum[i]-sum[j])^2 +M }  0<j<i 其中 sum[i]表示数字的前i项和. 相信都能理解上面的方程. 直接求解上面的方程的话复杂度是O(n^2) 对于500000的规模显然是超时的.下面讲解下如何用斜率

HDU 2829 Lawrence (斜率DP)

斜率DP 设dp[i][j]表示前i点,炸掉j条边的最小值.j<i dp[i][j]=min{dp[k][j-1]+cost[k+1][i]} 又由得出cost[1][i]=cost[1][k]+cost[k+1][i]+sum[k]*(sum[i]-sum[k]) cost[k+1][i]=cost[1][i]-cost[1][k]-sum[k]*(sum[i]-sum[k]) 代入DP方程 可以得出 y=dp[k][j-1]-cost[1][k]+sum[k]^2 x=sum[k]. 斜率s