51Nod 1510 最小化序列

2021-09-30 13:48:03 字數 1540 閱讀 7947

acm模版

這個題,打眼一看就是貪心,然後我就貪心寫了一下,wa

了三分之一,分析了一下,感覺只是貪心不行,還有 dp

搞搞才行……

首先,貪心的思路是,我們需要將資料分為

k 組,其中有 n%

k組的大小為 nk

+1,剩下的 k−

n%k 組有 nk

個。這個好理解,就不多說了,接著我們要將序列排序,因為當我們這樣分組時,最後結果其實就是各組最小花費的和,而各組的最小花費當然是選取若干個排序後是連續的數最佳,加減抵消後的結果就是每組最後乙個數減去第乙個數,當然,也就是最大的數減去最小的數。此時,剩下的問題就很明朗了,排序後的陣列如何劃分為上述

k 組使其和最小?這個部分自然就是動歸了。

其實,這裡的第二部分我們不用動歸也未嘗不可,用 df

s搜尋也許也是可以的,因為我們可以肯定的是,每次劃分一段區間作為一組數的時候,都要貪心的從左右兩側劃分,所以控制好未劃分區間即可。一直到劃分完後,判斷一下結果是否更優,當然,這種方法並不是特別好,時間消耗可能比較高,記憶化一下能提公升一些效率,但是還是不如 dp

省事兒,實在是下策。

也許,上邊就是我在胡謅,並不可行吧……懶得嘗試了。

#include 

#include

#include

using

namespace

std;

const

int maxn = 3e5 + 10;

const

int maxk = 5e3 + 10;

int n, k;

int a[maxn];

int dp[maxk][maxk];

template

inline

bool scan_d(t &ret)

while (c != '-' && (c < '0' || c > '9'))

sgn = (c == '-') ? -1 : 1;

ret = (c == '-') ? 0 : (c - '0');

while (c = getchar(), c >= '0' && c <= '9')

ret *= sgn;

return1;}

int main()

sort(a, a + n);

int t1 = n % k;

int t2 = k - t1;

k = n / k;

dp[0][0] = 0;

for (int i = 1; i <= t2; i++)

for (int j = 1; j <= t1; j++)

int k1, k2;

for (int i = 1; i <= t2; i++)

}printf("%d\n", dp[t2][t1]);

return

0;}

51nod1510 最小序列

現在有乙個長度為n的陣列a,另外還有乙個整數k。陣列下標從1開始。現在你需要把陣列的順序重新排列一下使得下面這個的式子的值盡可能小。特別的,你也可以不對陣列進行重新排列。單組測試資料。第一行包含兩個整數n,k 2 n 3 10 5,1 k min 5000,n 1 第二行包含n個整數 a 1 a 2...

字典序最小的子串行 51Nod 1255

記錄每個字母出現的最早和最晚位置 然後掃一遍 維護乙個單調棧 但是並不只考慮字母大小 還要考慮出現最早最晚位置 如果當前字母比棧頂元素小 並且棧頂元素在在之後還會出現 那就換掉這個棧頂 include using namespace std const int maxn 1e5 10 const i...

51nod動態規化 最長單調遞增子串行

題目 給出長度為n的陣列,找出這個陣列的最長遞增子串行。遞增子串行是指,子串行的元素是遞增的 例如 5 1 6 8 2 4 5 10,最長遞增子串行是1 2 4 5 10。輸入 第1行 1個數n,n為序列的長度 2 n 50000 第2 n 1行 每行1個數,對應序列的元素 10 9 s i 10 ...