快THUWC了,因此補一下之前的題。
真的是一道神題啊,網上的題解沒幾篇,並且還都看不懂,我作了一天才作出來。ios
傳送到LOJ:(>人<;)spa
直接切入正題。
咱們考慮區間dp,第一件事是離散化。
而後用\(g(i,j)\)表示消除完閉區間\([i,j]\)的最小費用。
而後呢?怎麼轉移?exm???
這時候會有一個很是天然的想法。
計算\(g(i,j)\)的時候,咱們枚舉兩個數\(l,r\),而後保留下值在閉區間\([l,r]\)以內的全部數,先消除掉其餘的數字,就只剩\([l,r]\)以內的數字了,再一次性消除掉她們。
時間複雜度\(O(n^5)\),可是顯然是錯的。
錯在哪裏呢?大概是錯在下面這種狀況,我懶得構造具體的反例了。
對於一組數字\(abcabca\),咱們能夠先消除掉中間的\(a\),再消除掉\(bcbc\),最後再消除掉\(aa\),在咱們的dp裏面彷佛並無考慮到這種狀況。
由於\(aa\)是最後消除掉的,所以若是咱們選擇保留\(a\)的話,會保留下來全部的\(a\)。
咱們太仁慈了,保留下來了\([l,r]\)之間的全部的數字,其實不必定要保留全部數字。
怎麼辦呢?
腦洞大開!
咱們用\(f(i, j, l, r)\)表示,消除完在閉區間\([i,j]\)以內的,除了值在\([l,r]\)之間的全部數字。
注意,在\([l,r]\)之間的數字,能夠消除,也能夠不消除。
而後顯然有這個東西:
code
#include <cstring> #include <algorithm> #include <cstdio> #include <iostream> using namespace std; const int N = 52; const int W = 1010; const int INF = 0x3f3f3f3f; int _w; int bmin( int &a, int b ) { return a = b < a ? b : a; } int n, a, b, w[N]; int vis[W], num[N], m; int f[N][N][N][N], g[N][N]; int F( int, int, int, int ); int G( int, int ); void discrete() { for( int i = 1; i <= n; ++i ) vis[w[i]] = 1; m = 1; for( int i = 1; i < W; ++i ) if( vis[i] ) vis[i] = m, num[m++] = i; --m; for( int i = 1; i <= n; ++i ) w[i] = vis[w[i]]; } bool contain( int i, int j, int l, int r ) { for( int p = i; p <= j; ++p ) if( w[p] >= l && w[p] <= r ) return true; return false; } bool all( int i, int j, int l, int r ) { for( int p = i; p <= j; ++p ) if( w[p] < l || w[p] > r ) return false; return true; } int F( int i, int j, int l, int r ) { int &now = f[i][j][l][r]; if( now != -1 ) return now; if( all(i, j, l, r) ) return now = 0; if( !contain(i, j, l, r) ) return now = G(i, j); now = INF; for( int k = i; k < j; ++k ) { bmin( now, F(i, k, l, r) + F(k+1, j, l, r) ); bmin( now, G(i, k) + F(k+1, j, l, r) ); } // printf( "f[%d][%d][%d][%d] = %d\n", i, j, l, r, now ); return now; } int G( int i, int j ) { int &now = g[i][j]; if( now != -1 ) return now; now = INF; for( int l = 1; l <= m; ++l ) for( int r = l; r <= m; ++r ) if( contain(i, j, l, r) ) { int u = num[l], v = num[r]; bmin( now, F(i, j, l, r) + (v-u)*(v-u)*b + a ); } // printf( "g[%d][%d] = %d\n", i, j, now ); return now; } int main() { cin >> n >> a >> b; for( int i = 1; i <= n; ++i ) cin >> w[i]; discrete(); memset(f, -1, sizeof f); memset(g, -1, sizeof g); printf( "%d\n", G(1, n) ); return 0; }