有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...