動態規劃 區間型

2021-10-02 08:26:51 字數 3915 閱讀 4526

概述

最長的回文序列

取數是否必勝

給定乙個序列/字串,進行一些操作,最後一步會將序列/字串去頭/去尾

剩下的會是乙個區間[i, j]

狀態自然定義為f[i][j],表示面對子串行[i, …, j]時的最優性質

1. 題目描述

1. 給定乙個字串s,長度是n,找到它最長的回文子串行的長度

例子:

輸入:「bbbab」

輸出:4 (「bbbb」)

2. 思路

確定狀態

1. 最優策略產生的最長的回文子串t,長度是m

2. 情況一:回文串長度是1,即乙個字母

3. 情況二:回文串長度大於1,那麼必定有t[0]=t[m-1]

4. 設t[0]是s[i],t[m-1]是s[j],t剩下的部分t[1…m-2]仍然是乙個回文串,而且是s[i+1…j-1]的最長回文串

5. 所以要求s[i…j]的最長回文子串,如果s[i]=s[j],需要知道s[i+1…j-1]的最長回文子串

6. 否則答案是s[i+1…j]的最長回文子串或者s[i…j-1]的最長回文子串

轉移方程

狀態:設f[i][j]=為s[i…j]的最長回文子串的長度

初始條件和邊界情況

初始條件

1. f[0][0]=f[1][1]=…=f[n-1]][n-1]=1,乙個字母也是乙個長度為1的回文串

2. 如果s[i] = s[i+1],f[i][i+1] = 2

3. 如果s[i] != s[i+1],f[i][i+1] = 1

計算順序

1. 區間型動態規劃不能按照 i 的順序去計算,要按照長度 j-i 從小到大的順序去算

長度1:f[0][0],f[1][1],....f[n-1][n-1]

長度2:f[0][1],f[1][2],....f[n-2][n-1]

...長度n:f[0][n-1]

答案是 f[0][n-1]

3. **實現

public static int longestpalindromesubseq(string ss) 

if(n ==1

) int

f = new int

[n][n]

;for

(int i =

0; i < n; i++)

for(int i =

0; i < n -

1; i++)

//len表示子串長度

for(

int len =

3; len <= n; len++) }}

return f[0]

[n -1]

; }

1. 題目描述

給定乙個序列a[0],a[1],…,a[n-1],兩個玩家輪流取數,每人每次只能取第乙個數或者最後乙個數,問先手是否必勝(如果數字一樣,也算先手勝)

例子:輸入:[1, 5, 233, 7]

輸出:true(先手取走1,無論後手取哪個,先手都能取走233)

2. 思路

確定狀態

1. 設已方數字和是a,對手數字和是b,目標是a>=b,等價於a-b>=0,也就是說已方和對手都存在著自己的數字和與對手的數字和之差,分別記為sa=a-b,sb=b-a

2. 當已方取走乙個數字m後,對於已方來說,sa=-sb+m,現在已方有兩種選擇,取第乙個數字m1或最後乙個數字m2,為了最大化sa,應該選擇較大的那個sx

3. 如果a第乙個取走a[0],則b面對a[1,…n-1],b的最大數字差是sb,a的數字差是a[0]-sb

4. 如果a第一步取走a[n-1],b面對a[0,…,n-2],b的最大數字差sb,a的數字差是a[n-1]-sb

5. 當b面對a[1…n-1],b這時是先手,但此時數字少了乙個

轉移方程

狀態:設f[i][j]為一方先手在面對a[i…j]這些數字時,能得到的最大的與對手的數字差

初始條件和邊界情況

初始條件

1. 只有乙個數字a[i]時,已方得a[i]分,對手0分,數字差為a[i],即f[i][i]=a[i]

計算順序

1. 區間型動態規劃不能按照 i 的順序去計算,要按照長度 j-i 從小到大的順序去算

長度1:f[0][0],f[1][1],…f[n-1][n-1]

長度2:f[0][1],f[1][2],…f[n-2][n-1]

…長度n:f[0][n-1]

答案是如果 f[0][n-1]>=0,先手必勝,否則必輸

3. **實現

public static boolean firstwillwin2(

int[

] a)

for(int len =

2; len <= n; len++)

}return f[0]

[n -1]

>=0;

}

1. 題目描述

給定乙個字串s,按照樹結構每次二分成左右兩個部分,直至單個字元,在樹上某些節點交換左右兒子,可以形成新的字串

判斷乙個字串t是否由s經過這樣變換而成

例子:輸入:s=「great」 t=「rgtae」

輸出:true

2. 思路

確定狀態

如果t長度和s長度不一樣,那麼肯定不能由s變成而來

如果t是s變換而來的,並且知道s最上層二分被分成s=s1s2,那麼一定有:

1. t也有兩部分t=t1t2,t1是s1變換而來的,t2是s2變換而來的

2. t也有兩部分t=t1t2,t1是由s2變換而來的,t2是由s1變換而來的

要求t是否由s變換而來的

1. 需要知道t1是否由s1變換而來的,t2是否由s2變換而來的

2. 需要知道t1是否由s2變換而來的,t2是否由s1變換而來的

s1,s2,t1,t2長度更短,即為子問題

轉移方程

狀態:設f[i][j][k][h]表示t[k…h]是否由s[i…j]變換而來

這裡所有的串都是s和t的子串,且長度一樣,所以每個串都可以用(起始位置,長度)表示

例如:s1長度是5,在s中位置7開始

t1長度是5,在t中位置0開始

可以用f[7][0][5]=ture/false表示s1能否通過變換成為t1

狀態:設f[i][j][k]表示s1能否通過變換成為t1

1. s1為s從字串i開始的長度為k的子串

2. t1為t從字串j開始的長度為k的子串

初始條件和邊界情況

初始條件

1. 如果s[i]=t[j],f[i][j][1]=true,否則f[i][j][1]=false

計算順序

1. 按照k從小到大的順序進行計算

f[i][j][1], 0<=i

3. **實現

public static boolean isscramble(string ss1, string ss2) 

boolean

f = new boolean

[n][n]

[n +1]

;for

(int i =

0; i < n; i++)

}for

(int len =

2; len <= n; len++)

}for

(int w =

1; w <= len -

1; w++) }}

}}return f[0]

[0][n]

; }

動態規劃 區間

真是乙個思維巧妙的毒瘤題。因此我們直接利用上面的性質來dp.設f i j f i j f i j 表示線段按右端點排序後第i ii條,j,rj j,r j j,rj 只被覆蓋了一次的最小代價,1,rj 1,r j 1,rj 全部被覆蓋的方案數。那麼,我們需要根據上乙個線段j jj和i ii的位置關係...

模板 動態規劃 區間dp

因為昨天在codeforces上設計的區間dp錯了 錯過了上紫的機會 覺得很難受。看看學長好像也有學,就不用看別的神犇的了。區間dp處理環的時候可以把序列延長一倍。for int len 1 len n len 首先,使用四邊形優化要滿足下面的性質 當小區間包含在大區間中,則小區間的成本不高於大區間...

動態規劃 區間DP 計數類DP

acwing 282.石子合併 區間dp的特點是狀態表示的時候表示的是某乙個區間的情況 動態規劃模型分析 即 不管石子如何合併,最後一步的操作一定是將兩堆石子合併 把步驟回到倒數第一步。當在做最後一次操作時遍歷所有區間,將最後一步最小的情況記錄進f陣列裡 部分如下 全域性變數 const int n...