概述
最長的回文序列
取數是否必勝
給定乙個序列/字串,進行一些操作,最後一步會將序列/字串去頭/去尾
剩下的會是乙個區間[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...