HDU 3480 Division(斜率DP裸题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480

题目大意:将n个数字分成m段,每段价值为(该段最大值-该段最小值)^2,求最小的总价值。

解题思路:很单纯的斜率优化DP,得出状态转移方程:dp[i][j]=min{dp[k][j-1]+(a[i]-a[k+1])^2}(j-1<=k<i),然后斜率优化降到O(n^2)就好了。

     注意:数据类型建议用int,不要用long long,后者乘法计算时间是前者的四倍,否则C++可能会超时。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 const int N=1e4+5;
 8 
 9 int head,tail;
10 int dp[N][5005],a[N],q[N];
11 
12 int getUP(int m,int k,int j){
13     return dp[k][j-1]+a[k+1]*a[k+1]-dp[m][j-1]-a[m+1]*a[m+1];
14 }
15 
16 int getDOWN(int m,int k){
17     return 2*(a[k+1]-a[m+1]);
18 }
19 
20 //dp[i][j]=min{dp[k][j-1]+(a[i]-a[k+1])^2}
21 int getDP(int i,int j,int k){
22     return dp[k][j-1]+(a[i]-a[k+1])*(a[i]-a[k+1]);
23 }
24 
25 int main(){
26     int t,cas=0;
27     scanf("%d",&t);
28     int cnt=0;
29     while(t--){
30         int n,m;
31         scanf("%d%d",&n,&m);
32         for(int i=1;i<=n;i++){
33             scanf("%d",&a[i]);
34         }
35         sort(a+1,a+1+n);
36         for(int i=1;i<=n;i++){
37             dp[i][1]=(a[i]-a[1])*(a[i]-a[1]);
38         }
39         
40         for(int j=2;j<=m;j++){
41             head=tail=0;
42             q[tail++]=j-1;
43             for(int i=j;i<=n;i++){
44                 cnt++;
45                 while(head+1<tail&&getUP(q[head],q[head+1],j)<=a[i]*getDOWN(q[head],q[head+1])){
46                     head++;
47                 }
48                 dp[i][j]=getDP(i,j,q[head]);
49                 while(head+1<tail&&getUP(q[tail-1],i,j)*getDOWN(q[tail-2],q[tail-1])<=getUP(q[tail-2],q[tail-1],j)*getDOWN(q[tail-1],i)){
50                     tail--;
51                 }
52                 q[tail++]=i;
53             }
54         }
55         printf("Case %d: %d
",++cas,dp[n][m]);
56     }
57     return 0;
58 }
原文地址:https://www.cnblogs.com/fu3638/p/7850650.html