HDU3480-Division-斜率dp

首先想到的就是sort一下,然后每个集合都在排过序的数组里面取,不重复。

这样就推出公式dp[i][j] = min(dp[k][j-1] + (s[i]-s[k+1])^2)

其中dp[i][j]为在第i位完成j个分组的。

不考虑分组的情况下跟打印文章那题一样。考虑上需要有M个分组,就是两层for循环的dp。

这里往维护的凸包里添加点的时候,要等这一层全部解决之后再一起添进去。保证处理dp第j层时考虑的都是j-1层的情况。

还有就是初始化了。

O(N*M)大概5e7 有点卡,第一次写了个set就TLE了

 1 #include <set>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define LL long long
 6 using namespace std;
 7
 8 const int maxn = 1e4+10;
 9 const int maxm = 5e3+10;
10
11 struct Point{
12     LL x,y;
13     Point(LL _x=0,LL _y=0) :x(_x),y(_y){}
14     bool operator < (const Point &rhs) const
15     {
16         if(x == rhs.x) return y < rhs.y;
17         else return x <rhs.x;
18     }
19     LL operator ^(const Point &rhs) const
20     {
21         return x*rhs.y - y*rhs.x;
22     }
23     Point operator - (const Point &rhs) const
24     {
25         return Point(x-rhs.x,y-rhs.y);
26     }
27 };
28 LL func(Point p,LL k)
29 {
30     return p.y - k*p.x;
31 }
32
33 struct SlopeDP
34 {
35     Point ch[maxn];
36     int head,tail;
37     void init()
38     {
39         tail = 1;head = 0;
40     }
41     void push(Point u)
42     {
43         while(head >= 1 && ((ch[head]-ch[head-1])^(u-ch[head]) )<=0) head--;
44         ch[++head] = u;
45     }
46     Point pop(int k)
47     {
48         while(tail < head && func(ch[tail],k) >= func(ch[tail+1],k) ) tail++;
49         return ch[tail];
50     }
51 };
52 int T,N,M;
53 LL s[maxn],dp[maxn][maxm];
54 //set <Point> st;
55 Point save[maxn];
56
57 int main()
58 {
59     scanf("%d",&T);
60     int cas = 0;
61     while(T--)
62     {
63         memset(dp,0,sizeof dp);
64         scanf("%d%d",&N,&M);
65         for(int i=1;i<=N;i++)
66         {
67             scanf("%d",&s[i]);
68         }
69         sort(s+1,s+1+N);
70         SlopeDP H;
71         H.init();
72         //st.clear();
73         int cnt = 0;
74         for(int i=1;i<=N;i++)
75         {
76             dp[i][1] = (s[i] - s[1])*(s[i] - s[1]);
77             //st.insert(Point(s[i],s[i]*s[i]+dp[i-1][1]));
78             save[cnt++] = Point(s[i],s[i]*s[i]+dp[i-1][1]);
79         }
80
81         for(int j=2;j<=M;j++)
82         {
83             H.init();
84             for(int i=0;i<cnt;i++) H.push(save[i]);
85             cnt = 0;
86             for(int i=j;i<=N;i++)
87             {
88                 Point u = H.pop(2*s[i]);
89                 dp[i][j] = -2*s[i]*u.x + u.y + s[i]*s[i];
90                 //printf("i:%d %d x:%d y:%d k:%d\n",i,dp[i][j],u.x,u.y,-2*s[i]);
91                 //H.push(Point(s[i+1],s[i+1]*s[i+1]+dp[i][j]));
92                 save[cnt++] = Point(s[i+1],s[i+1]*s[i+1]+dp[i][j]);
93             }
94         }
95         printf("Case %d: %lld\n",++cas,dp[N][M]);
96     }
97 }
时间: 2024-11-03 20:52:12

HDU3480-Division-斜率dp的相关文章

HDU 3480 - Division - [斜率DP]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 999999/400000 K (Java/Others) Little D is really interested in the theorem of sets recently. There's a problem that confused him a long time.   

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