SRM558 DIV1 275 Stamp

スタンプの長さ(L = 1 〜 desiredColor.size())と、最初に何色で塗るか(3通り)を全通り試す。

int n=desiredColor.size();
int res=inf;
for(int L=1;L<=n;++L) {
    for(int c=1;c<=3;++c) { // R=1, G=2, B=3
        res=min(res, L*stampCost + (長さL、最初にcで塗ったときの最小push回数)*pushCost);
    }
}

最小push回数を求める部分は、
・重ね塗りできるのは同じ色だけ
・まだ塗っていないところは何色でもいい
・ボードからスタンプがはみ出してはいけない
というルールに気をつけて左から右に塗っていく感じでメモ化全探索。

#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
#define REP(i,a,b) for(int i=a;i<b;++i)
#define rep(i,n) REP(i,0,n)
typedef long long ll;

int a[51],n;
ll memo[4][51];
const ll inf=(1LL<<40);
class Stamp {
    // 長さLのスタンプでk〜k+L-1番目のセルを色cで塗った場合、
    // k番目以降をdesiredColorに合わせるための最小push回数
    ll func(int L, int c, int k)
    {
        // はみ出しちゃダメ
        if (k+L>n) return inf;
        // desiredColorじゃない色で塗っちゃダメ
        rep(i,L) if (a[k+i] && a[k+i]!=c) return inf;
        // 最後まで塗れたらOK
        if (k+L==n) return 1;

        ll& res=memo[c][k];
        if (res) return res;
        res=inf;
        // [k+1,k+L)の範囲はcと同じ色でしか塗れない
        REP(i,1,L) res=min(res,func(L,c,k+i)+1);
        // まだ塗っていないセルは何色で塗ってもいい
        REP(i,1,4) res=min(res,func(L,i,k+L)+1);
        return res;
    }
    public:
    int getMinimumCost(string desiredColor, int stampCost, int pushCost)
    {
        ll res=inf;
        n=desiredColor.size();
        rep(i,n)switch(desiredColor[i]){
            case 'R': a[i]=1; break;
            case 'G': a[i]=2; break;
            case 'B': a[i]=3; break;
            default: a[i]=0;
        }
        // スタンプの長さ、最初に何色で塗るかを全探索
        REP(L,1,n+1) REP(c,1,4) {
            memset(memo,0,sizeof(memo));
            res=min(res,L*stampCost+func(L,c,0)*pushCost);
        }
        return int(res);
    }
};