1. 程式人生 > >洛谷 P3146 248 題解

洛谷 P3146 248 題解

為什麽 div ace 更新 quest break 超出 def nbsp

https://www.luogu.org/problemnew/show/P3146

區間dp,這次設計的狀態和一般的有一定的差異。

這次我們定義$dp[i][j]$表示$[i,j]$的可以合並出來最大取值,而不是合並區間$[i,j]$的最大取值。

同樣的我們枚舉區間長度,枚舉左端點,求出右端點。

枚舉$i$到$j$之間的每一個分割點,判斷兩點之間是否可以合並,取價值更高的答案。

$$dp[i][j]=max(dp[i][j],dp[i][k]+1) [dp[i][k]==dp[i][k+1]$$

Question 1:其他的點不需要更新,為什麽?

這就要看我們設計的狀態了,我們定義的是區間[i,j]可以合並出來的最大值,答案唯一,當然不能用其位置的更新了。

Question 2:答案是什麽?

註意這裏的答案不一定是$dp[1][n]$,你想當我們計算區間[1,n]時所有的$dp[i][k]!=dp[k+1][j]$那麽區間$[1,n]$的答案為$0$,答案在之前已經得出,所以我們在過程中記錄一下就好了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
using
namespace std; #define LL long long #define mod int(1e9+7) int n,a[250],dp[250][250],ans; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); dp[i][i]=a[i]; //初始化dp數組 } for(int len=2;len<=n;len++) { for(int
i=1;i<=n;i++) { int j=i+len-1; if(j>n)break; //超出長度限制 for(int s=i;s<j;s++) { if(dp[i][s]==dp[s+1][j])dp[i][j]=max(dp[i][j],dp[i][s]+1); } ans=max(dp[i][j],ans); //記錄答案 } } printf("%d",ans); }

洛谷 P3146 248 題解