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 }

 

posted @ 2016-07-30 22:03  Helica  阅读(482)  评论(0编辑  收藏  举报