DP的另乙個角度 數列劃分

2021-06-16 23:13:54 字數 1273 閱讀 3844

有個長度小於40000數列,把它分成若干段,使得各段花費總和最小。一段的花費為該段不同元素的個數(不妨設有x)個,那麼花費為x的平方。

看到題目,不難想到動態規劃的做法。設f(i)為前i個元素最小的花費,然後列舉最後一段放多少個元素,不妨設為k個,那麼f(i)=min。這當然是可行的,但時間複雜度不容樂觀。

再思考,發現每一段最多只有200個不同的元素,若大於200個,它的花費早已超過40000了,那還不如乙個元素作為一段,花費還小於或等於40000。並且,在包括同樣多不同元素的情況下,元素個數必然越多越好。比如:就比好,因為它們都有兩個不同的元素,但前者有4個元素,後者只有3個。

所以f(i)的轉移只需要列舉200個不同的f(j),j從這題中可以知道dp的優化不一定都是用什麼資料結構。可以從中發現一些規律。主要思考的如何快速求出當前狀態的值。一般有三種手段:一是通過一些資料結構,例子數不勝數;二是通過前面已經求出來的值作為參考,整數拆分就是這類問題;三是像這題一樣,通過減少轉移的次數,來達到目標。

我是把所有的j位置找出來,其實沒必要用鍊錶……當然,還有其他方法,可以直接維護j的位置,因為i每次只加一,維護就容易了。

#include #include #include #include using namespace std;

const int n = 40007;

int n, m;

int d[n], f[n];

int set[n], size;

const int p = 8000007;

int from[n], to[p], next[p], val[p], nedge;

void insert(int a, int b, int c)

int main()

int forj = min((int) floor(sqrt(n)), m);

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

//f[cur - 1] <?= f[i - 1] + j * j;

insert(cur - 1, i - 1, j * j);

set[d[i]] --;

if (set[d[i]] == 0) size --;

} }for (int i = 1; i <= n; i ++)

for (int e = from[i]; e; e = next[e])

f[i] <?= f[to[e]] + val[e];

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

return 0;

}

從另乙個角度看自己

從去年11月15號寫下豪言壯語 每天更新一篇,到現在一篇也沒有更新,確實是吹牛吹大了。當然,我並不是忘記了天天積累的重要性,而是,稍微換了乙個地方踐行了不一樣的東西。我從2016年開始,一直在嘗試著通過踐行來重新認知自己,漸漸我發現,很多道理是相通的,很多踐行也是相通的,沒有呈現出來,不代表什麼都沒...

另乙個自己

人們常說 人貴有自知之明 可是話說回來,又有幾人能真正的了解自己呢?我覺得我就是乙個很沒有自知之明的人。生於89年的我,到了今年的生日就28周歲了。都說三十而立,正所謂成家立業,可以回過頭發現自己可以稱得上 一無是處,一無所有 曾幾何時,還是鄰居家叔叔阿姨教育孩子的榜樣 曾幾何時父母因為自己考個好大...

從另乙個角度去解決客戶的需求

重量級客戶的需求終於滿足了,但是又出了新情況。將軍 一休啊,這屏風上畫的老虎每晚都會走出屏風作怪,你來想辦法捉住它吧。注意,客戶是將軍。客戶之前要求顯示虎威,真正的老虎的虎威。於是,好不容易實現了。沒想到他和葉公是鄰居。但是,畫虎容易捉住虎難啊。我該如何解決客戶這個問題,按照將軍的思路去將老虎捉住嗎...