srm 558 dv2 500pt
做了好长时间,害的苏神又跟我强调了一遍做dp的技巧。。。
首先当然要枚举stamp的长度len了,然后设dp[j]['C']表示这个位置涂成c颜色最少需要几次,假如用c[k]染第j个格子,看j的前len-1个位置合不合法,合法就是颜色和第j格相同或者是‘*’啦,如果不合法,就跳出,如果合法,就更新dp[j]['C'] = min{dp[j]['C'],dp[k]['C']+1 (j-len<k<j)};最后还有一种情况别漏了,那就是可以前j-len格的最小染色次数+1,min(dp[j-i]['R'],dp[j-i]['G'],dp[j-i]['B'])+1
代码贴出来。。
# include <cstdio> # include <iostream> # include <algorithm> # include <string> # include <cstring> # define maxi 0xfffffff using namespace std; int dp[100][260]; char c[] = {'R','G','B'}; class Stamp { public: int getMinimumCost(string desiredColor, int stampCost, int pushCost) { int i,j,k,N = desiredColor.size(),ans = maxi,m; string s; for (i=0;i<N;++i) s[i+1] = desiredColor[i]; for (i=1;i<=N;++i) { for (j=1;j<=N;++j) dp[j]['R'] = dp[j]['G'] = dp[j]['B'] = maxi; dp[0]['R'] = dp[0]['G'] = dp[0]['B'] = 0; for (j=i;j<=N;++j) for (k=0;k<3;++k) { int flag = 0; if (c[k]!=s[j]&&s[j]!='*') continue; for (m=j-1;m>j-i;--m) { if (s[m]!=c[k]&&s[m]!='*') { dp[j][c[k]] = maxi; flag = 1; break; } dp[j][c[k]] = min(dp[j][c[k]],dp[m][c[k]]+1); } if (!flag) dp[j][c[k]] = min(dp[j][c[k]],min(dp[j-i]['R'],min(dp[j-i]['G'],dp[j-i]['B']))+1); } if (min(dp[N]['R'],min(dp[N]['G'],dp[N]['B']))<maxi) ans = min(ans,i*stampCost+min(dp[N]['R'],min(dp[N]['G'],dp[N]['B']))*pushCost); } return ans; } };