jzoj 2184 羊羊列隊

2022-05-16 22:23:07 字數 1506 閱讀 8303

有n個人,要分成m個班,每個班至少1人。每班貢獻為\((max-min)^2\),求最小貢獻值。

\(1<=n<=10000,1<=m<=1000,1<=ai<=1000000\)

很容易想到\(dp\)。

由於我們要使貢獻最小,所以我們不妨將它排序,然後每次取連續的一段,這樣可以保證值最小。

這題由於要剛好分成\(m\)個班,所以我們必須要多設一維\(dp\)。

設\(f[i][j]\)表示到第\(i\)個人,往前分了\(j\)個班的最小貢獻。

很容易得到轉移方程:

\[f[i][j] = min(f[k][j - 1] + (a[i] - a[k + 1])^2)

\]時間為\(o(n^2m)\),過不了,所以我們考慮優化。

斜率優化即可。

#include #include #include #define n 10010

#define m 1010

#define mem(x, a) memset(x, a, sizeof x)

#define fo(x, a, b) for (int x = a; x <= b; x++)

using namespace std;

int n, m, a[n], f[n][m], g[n], l = 1, len = 0;

inline int read()

int sqr(int x)

int left(int x, int y, int k)

int right(int x, int y)

int main()

} printf("%d\n", f[n][m]);

return 0;

}

這題可以用凸優化來弄。\(o(nlogn)\)

凸優化:對於每一次的選取加乙個\(k\)的代價。

顯然,\(k\)越大分成的組數越小,反之越大。

所以,我們可以二分\(k\),最後答案便是\(f[n]-m*k\)

#include #include #include #define n 10010

#define m 1010

#define mem(x, a) memset(x, a, sizeof x)

#define fo(x, a, b) for (int x = a; x <= b; x++)

using namespace std;

int n, m, a[n], f[n][2], g[n], l = 1, len = 0;

inline int read()

int sqr(int x)

int left(int x, int y)

int right(int x, int y)

void check(int x)

}int main()

printf("%d\n", f[n][0] - mid * m);

return 0;

}

2 18學習記錄

主要內容 css知識複習 字元轉換 text transform none uppercase lowercase capitalize text decoration none underline overline through line blink 斜體 font style italic f...

2 18 陣列分割

題目概述 有乙個沒有排序,元素個數為2n的正整數陣列。要求把它分割為元素個數為n的兩個陣列,並使兩個子陣列的和最接近。假設陣列a 1.2n 所有元素的和是sum。模仿動態規劃解0 1揹包問題的策略,令s k,i 表示前k個元素中任意i個元素的和的集合。顯然 s k,1 s k,k s k,i s k...

2 18 共享記憶體通訊

1.基本概念 共享記憶體是ipc機制中的一種,作用是使得兩個不相關的程序訪問同一段記憶體,是一種程序間傳輸資料的一種有效方式。2.函式學習 2.1 建立 獲取共享記憶體 函式名 shmget 函式原型 man shmget int shmget key t key,size t size,int s...