1. 程式人生 > >cf 1114d 區間dp 0,1標記左右

cf 1114d 區間dp 0,1標記左右

back nbsp 標記 div ++ fine ret ace 左右

題意:

  一個顏色序列,每個位置有一個顏色,選擇一個起始位置,每次可以改變包含這個位置的顏色段,將整個顏色段修改為任意一個顏色, 問最少操作多少次。n<=5000

思路:

  區間dp。按照最少的原則,假設dp[i][j]已經是處理好的了, 那麽由於要求最少,

  那麽這時候的顏色要麽是a[i]色,要麽是a[j]色,所以用dp[i][j][0/1]表示。把這一段變成a[i]/a[j]顏色的最少次數,

註意:

  那麽更新的時候要註意是d[i][j][0]由 dp[i+1][j]而來,dp[i][j][1]由dp[i][j-1][.]而來。

  比賽時,由於多更新就wa了。。因為dp[i][j][x] 就已經知道 新加入的是i,還是j了

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(v) v.begin(),v.end()
#define mem(a) memset(a,0,sizeof(a))

const int N = 5004;
const ll mod =1e9+7;
const int INF = 1e9+4;
const double eps = 1e-7
; int a[N],b[N]; string s; int n,m,t; int d[N][N][2]; int main(){ cin>>n; for(int i=1;i<=n;++i) cin>>a[i]; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) d[i][j][0]=d[i][j][1]=INF; for(int i=1;i<=n;++i) d[i][i][0]=d[i][i][1]=0
; for(int len=1;len<n;++len){ for(int i=1;i+len<=n;++i){ int j =i+len; //這裏註意 不要多更新。 //d[i][j][0] = d[i][j-1][0]+(a[j]!=a[i]); //d[i][j][0] = min(d[i][j][0],d[i][j-1][1]+(a[j]!=a[j-1]) ); d[i][j][0] = min(d[i][j][0],d[i+1][j][0]+(a[i]!=a[i+1]) ); d[i][j][0] = min(d[i][j][0],d[i+1][j][1]+(a[i]!=a[j])); d[i][j][1] = d[i][j-1][1]+(a[j]!=a[j-1]); d[i][j][1] = min(d[i][j][1],d[i][j-1][0]+(a[j]!=a[i])); //d[i][j][1] = min(d[i][j][1],d[i+1][j][0]+(a[i]!=a[i+1])); //d[i][j][1] = min(d[i][j][1],d[i+1][j][1]+(a[i]!=a[j])); } } cout<<min(d[1][n][0],d[1][n][1])<<endl; return 0; }

cf 1114d 區間dp 0,1標記左右