日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

删好串(区间dp)

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 删好串(区间dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

定義長度為 nnn 的“好”的串 aaa 滿足:

  • ∣ai?ai?1∣=1,i∈[2,n]|a_i-a_{i-1}|=1,i\in[2,n]ai??ai?1?=1,i[2,n]
  • ai≥ai?1+ai+12,i∈[2,n?1]a_i\ge \frac{a_{i-1}+a_{i+1}}{2},i\in[2,n-1]ai?2ai?1?+ai+1??,i[2,n?1]

給定長度為 nnn 的序列 a,va,va,v,每次選擇一段 aaa 的“好”子串刪除,剩下的子串拼接在一起。

若刪除子串長度為 xxx,則會獲得 vxv_xvx? 的價值。

不一定要刪完,求最大價值。

n≤400,∣vi∣≤1e5,1≤ai≤1e9n\le 400,|v_i|\le 1e5,1\le a_i\le 1e9n400,vi?1e5,1ai?1e9

solution

observation:子串要么是單增,要么是單減,要么是先單增后單減,即/,\,/\。顯然 \/ 情況下的最低點無法滿足條件 222

先不考慮“不一定全刪完”,我們就要求必須刪完。

fl,r:[l,r]f_{l,r}:[l,r]fl,r?:[l,r] 全部刪完的最大價值。顯然是區間 dpdpdp 轉移。(dpdpdp 轉移就是要歸到子問題上)

  • 考慮最后一次刪除 l,rl,rl,r 不是一起被刪的,那么肯定存在一個中間點 ppp 分割這段區間。

    fl,r←fl,p+fp+1,rf_{l,r}\leftarrow f_{l,p}+f_{p+1,r}fl,r?fl,p?+fp+1,r?

  • 考慮最后一次刪除 l,rl,rl,r 是一起被刪的。

    那么我們就需要知道最后一次的單增/單減序列的價值。

    gl,r:[l,r]g_{l,r}:[l,r]gl,r?:[l,r] 刪到只剩一個單增序列的最大價值。

    hl,r:[l,r]h_{l,r}:[l,r]hl,r?:[l,r] 刪到只剩一個單減序列的最大價值。

    我們直接枚舉兩個序列的交點,即最高點 iii

    fl,r←gl,i+hi,r+v(ai?2?al?ar+1)f_{l,r}\leftarrow g_{l,i}+h_{i,r}+v(a_i*2-a_l-a_r+1)fl,r?gl,i?+hi,r?+v(ai??2?al??ar?+1)

    當然還有只有單增/單減情況,但要求 al,ara_l,a_ral?,ar? 滿足相應大小關系。

    fl,r←gl,r+v(ar?al+1)al≤arf_{l,r}\leftarrow g_{l,r}+v(a_r-a_l+1)\quad a_l\le a_rfl,r?gl,r?+v(ar??al?+1)al?ar?

    fl,r←hl,r+v(al?ar+1)al≥arf_{l,r}\leftarrow h_{l,r}+v(a_l-a_r+1)\quad a_l\ge a_rfl,r?hl,r?+v(al??ar?+1)al?ar?

    至于 g,hg,hg,h 的轉移,同樣枚舉接在 rrr 前的元素 iii,即可變成子問題。

    gl,r←gl,i+fi+1,r?1ai+1=arg_{l,r}\leftarrow g_{l,i}+f_{i+1,r-1}\quad a_i+1=a_rgl,r?gl,i?+fi+1,r?1?ai?+1=ar?

    hl,r←hl,i+fi+1,r?1ai?1=arh_{l,r}\leftarrow h_{l,i}+f_{i+1,r-1}\quad a_i-1=a_rhl,r?hl,i?+fi+1,r?1?ai??1=ar?

最后再來個 dpi:[1,i]dp_i:[1,i]dpi?:[1,i] 一定刪掉 [k,i][k,i][k,i] 連續一段,但前面不要求刪完的最大價值。

枚舉 jjjdpj+fk,i→dpidp_j+f_{k,i}\rightarrow dp_idpj?+fk,i?dpi?,前綴最大值優化,轉移,dpndp_ndpn? 就是最后的結果了。

時間復雜度 O(n3)O(n^3)O(n3)

code

#include <bits/stdc++.h> using namespace std; #define maxn 405 #define int long long #define inf 0x3f3f3f3f int n; int v[maxn], a[maxn], dp[maxn]; int f[maxn][maxn], g[maxn][maxn], h[maxn][maxn];signed main() {freopen( "good.in", "r", stdin );freopen( "good.out", "w", stdout );scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &v[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );//f[l][r]:刪完[l,r]的最大價值for( int l = n;l;l -- )for( int r = l;r <= n;r ++ ) {f[l][r] = g[l][r] = h[l][r] = -inf;g[l][l] = h[l][l] = 0;for( int i = l;i <= r;i ++ ) {f[l][r] = max( f[l][r], f[l][i] + f[i + 1][r] );//case1 枚舉斷點if( a[i] - 1 == a[r] ) h[l][r] = max( h[l][r], h[l][i] + f[i + 1][r - 1] );//h[l][r]:將[l,r]刪到只剩一個下坡的最大價值 且l,r一定不被刪if( a[i] + 1 == a[r] ) g[l][r] = max( g[l][r], g[l][i] + f[i + 1][r - 1] );//g[l][r]:將[l,r]刪到只剩一個上坡的最大價值 且l,r一定不被刪if( a[l] <= a[i] and a[i] >= a[r] ) f[l][r] = max( f[l][r], g[l][i] + h[i][r] + v[(a[i] << 1) - a[l] - a[r] + 1] );//case2 枚舉最高點/連接點}if( a[l] <= a[r] ) f[l][r] = max( f[l][r], g[l][r] + v[a[r] - a[l] + 1] );//case3直接一個遞增序列無凸點if( a[l] >= a[r] ) f[l][r] = max( f[l][r], h[l][r] + v[a[l] - a[r] + 1] );//case4直接一個遞減序列無凸點}for( int i = 1;i <= n;i ++ ) {dp[i] = max( dp[i], dp[i - 1] );for( int j = i;j <= n;j ++ ) dp[j] = max( dp[j], dp[i - 1] + f[i][j] );//枚舉刪去[l,r]一段并加上前面剩下的最大值(利用前綴最大值優化dp)}printf( "%lld\n", dp[n] );return 0; }

總結

以上是生活随笔為你收集整理的删好串(区间dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。