首先想到的就是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 ",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 ",++cas,dp[N][M]); 96 } 97 }