區間DP 好題 String painter

2022-08-18 00:03:10 字數 3621 閱讀 6364

【題意】

給定兩個長度相同的字串a,b。每次操作都能把a中的任意乙個子段變成相同的字元,問最少操作多少次a能變成b?

【思路】

dp[i][j]表示i-j區間內的最少次數

先操作第二個字串,我們先假設第i個字元的位置需要噴刷一次,對於所有的dp[i][j]=dp[i+1][j]+1、

在i-j區間內,如果有第k個跟第i個相同,那麼就可以將i-j區間借助k分成兩部分dp[i][j]=min(dp[i+1][k]+dp[k+1][j]);

處理完第2個字串後,我們就要看第乙個字串究竟需要噴刷多少次了,用ans[i]記錄0-i區間第二個字串得出的噴刷次數,如果第乙個字串的i位置與第二個字串的i位置相同,那麼這個位置就不用噴刷了,ans[i]=ans[i-1],如果不相同,就要就要借助乙個位於o-i區間內的變數來分割開。

對於dp[i][j] 來說最差的就是1+dp[i+1][j]咯,那怎麼減少呢。。。 如果(i,j]裡面也有個k使得b[i] == b[k]那麼得話, 可以刷[i,k]這麼長的一段,那麼就有可能減少1.  但是存在問題,如果有一段跨越了k怎麼辦。。。 嗯,這個問題是不會出現的, 因為在[i,k]刷了b[i].如果跨越了k那麼之前在b[k]刷的顏色就沒了,所以是不允許有跨段的, 所以要寫成&&想寫成 dp[i][j] = dp[i+1][k] + dp[k+1][j]。 為什麼不可以跨段 可以思考  brbr 。 然後後來的那個  一段 要麼是可以分段刷的,要麼是不可以分段刷的。-

先計算出空串塗成b串的代價,用dp[i][j]儲存區間[i, j]塗成和b串一樣的最小代價。

因為字元都不相同,那麼代價的優化點就在於b串中相同的字元。

dp[i][j] = min(dp[i+1][j]+1, dp[i+1][k]+dp[k+1][j]); (i+1<=k<=j && b[k] == b[i])

b[i]可以在塗區間[i+1, k]時順帶塗上。  處理時需要注意邊界。

整理我們已經有的資訊dp[i][j],把空串變成b[i] - b[j]的字串所需的最小代價。

設定ans[i]為a[0] - a[i]的字串變成b[0] - b[i]所需的最小代價。

則狀態轉移:

a[i] == b[i]   ans[i] = ans[i-1];

a[i] != b[i]   ans[i] = min(ans[i], ans[j] + dp[j+1][i]); 把區間[j+1, i]當做空串來處理。

例如zzzzzfzzzzz,長度為11,我們就將下標看做0~10

先將0~10刷一次,變成aaaaaaaaaaa

1~9刷一次,abbbbbbbbba

2~8:abcccccccba

3~7:abcdddddcba

4~6:abcdeeedcab

5:abcdefedcab

這樣就6次,變成了s2串了

第二個樣例也一樣

先將0~10刷一次,變成ccccccccccb

1~9刷一次,cdddddddddcb

2~8:cdcccccccdcb

3~7:cdcdddddcdcb

4~6:cdcdcccdcdcb

5:cdcdcdcdcdcb

最後竟串尾未處理的刷一次

就變成了串2cdcdcdcdcdcd

所以一共7次

【accepted】

1 #include2 #include3 #include

4 #include5 #include6 #include7

using

namespace

std;

8const

int maxn=1e5+20;9

const

int maxm=1e6;

10const

int inf=0x3f3f3f3f;11

12struct

edge

13edge[maxm];

16int

tol;

17int

head[maxn];

18int

gap[maxn],dep[maxn],pre[maxn],cur[maxn];

19int num[1200

];20

void

init()

2126

27void addedge(int u,int v,int w,int rw=0)28

4041

int sap(int start,int end,int

n)4261}

62for(int i=pre[u];i!=-1;i=pre[edge[i^1

].to])

6367 u=start;

68 ans+=min;

69continue;70

}71bool flag=false;72

intv;

73for(int i=cur[u];i!=-1;i=edge[i].next)

7482}83

if(flag)

8488

int min=n;

89for(int i=head[u];i!=-1;i=edge[i].next)

9096

}97 gap[dep[u]]--;

98if(!gap[dep[u]])

99102 dep[u]=min+1

;103 gap[dep[u]]++;

104if(u!=start)

105108

}109

return

ans;

110}

111int

a[maxn];

112int

n,m;

113int bit[11

];114

115int

main()

116122

while(~scanf("

%d%d

",&n,&m))

123136

}137 num[temp]++;

138}

139int people=-inf;

140for(int i=1024;i>=0;i--)

141147

}148

int planet=people+1

;149

for(int i=0;i<=1024;i++)

150155 addedge(0

,i,num[i]);

156for(int k=0;k)

157162

}163

}164

for(int i=planet;i)

165169

170if(num[0

])171

175int res=sap(0,planet+m,planet+m+1

);176

if(res==n)

177180

else

181184

getchar();

185}

186return

0;

187 }

view code

codeforces 245H 區間DP 好題

方法一 先暴力求出每個字串是否是回文 列舉每個回文串的中間字元 儲存在dp i j 中 再從以求的小區間滾成大區間 view code include include char s 5005 int dp 5005 5005 int main for i 1 i len i 固定i,滾動j for ...

警衛安排(dp好題)

警衛安排 guard 題目描述 乙個重要的基地被分為 n 個連通的區域。出於某種神秘的原因,這些區域以乙個區域為核心,呈 一顆樹形分布。在每個區域安排警衛所需要的費用是不同的,而每個區域的警衛都可以望見其相鄰的區域,只要 乙個區域被乙個警衛望見或者是安排有警衛,這個區域就是安全的。你的任務是 在確保...

快餐問題(dp好題)

peter最近在r市開了一家快餐店,為了招攬顧客,該快餐店準備推出一種 該 由a個 漢堡,b個薯條和c個飲料組成。便宜。為了提高產量,peter從著名的麥當勞公司引進了n條 生產線。所有的生產線都可以生產漢堡,薯條和飲料,由於每條生產線每天所能提供的生產時間是有 限的 不同的,而漢堡,薯條和飲料的單...