NC14055 C.Cities(區間 dp)
阿新 • • 發佈:2021-11-08
目錄
Description
有 \(n\) 個數,如果一個連續的區間數都相同,那麼可以將它們全部變為另一個數,最後整個區間都變為同一個數的最小運算元是多少
State
\(1<=n<=5000\)
\(1<=a[i]<=n\)
Input
2 8 4 3 1 2 1 1 3 3 5 1 2 3 2 1
Output
3
2
Solution
如果一個區間 \([i+1,j]\) 上至少存在一個 \(k\),使得 \(a[i]=a[k]\) ,那麼將 \([i+1,k]\) 全部變為 \(a[i]\) 的次數就是將 \([i,k]\) 全部變為 \(a[i]\) 的答案,而將 \([i,j]\) 全部變為 \(a[i]\) 還需要將 \([k+1,j]\) 變為 \(a[i]\), 也就是說 \([k+1,j]\) 區間上的數全部與 \(a[k]\) 相同,所以方程為
\[dp[i][j]=dp[i+1][k]+dp[k][j] \]如果這個區間上一個 \(k\) 也不存在,由於上述策略
Code
const int N = 5000 + 5; int n, m, k, _; int a[N]; int dp[N][N]; int nxt[N], head[N]; void clear() { rep(i, 1, n) head[i] = 1e9, nxt[i] = 0; for(int len = 1; len <= n; len ++){ for(int i = 1; i <= n; i ++){ int j = i + len - 1; if(j > n) break; dp[i][j] = 1e9; } } } void sol() { rep(i, 1, n) dp[i][i] = 0; rep(i, 1, n - 1) dp[i][i + 1] = (a[i] != a[i + 1]); for(int len = 3; len <= n; len ++){ for(int i = 1; i <= n; i ++){ int j = i + len - 1; if(j > n) break; dp[i][j] = dp[i + 1][j] + 1; for(int k = nxt[i]; k <= j; k = nxt[k]){ dp[i][j] = min(dp[i][j], dp[i + 1][k] + dp[k][j]); } } } pd(dp[1][n]); } signed main() { // IOS; rush(){ sd(n); clear(); for(int i = 1; i <= n; i ++){ sd(a[i]); if(a[i] == a[i - 1]){ i --; n --; } } for(int i = n; i; i --){ nxt[i] = head[a[i]]; head[a[i]] = i; } sol(); } // PAUSE; return 0; }