CS Academy Lightbulbs

リンク : https://csacademy.com/contest/archive/task/lightbulbs/statement/

問題概要

01から成る文字列が入力される。i番目が0の場合電球iがついてなくて、i番目が1の場合電球iがついているとする。電球iの操作できる条件が電球i+1がついていて、電球i+2,i+3,i+4...がすべて消えているときである。このとき、すべての電球を消すための最小回数を求めよ。

解説

1のとき、1回、10のとき、3回、100のとき、7回...1と0がn-1個のとき、2n-1回必要ということが実験するとわかる。そこでdp[i][j]を後ろからi番目の電球がjであり(j=0,1)、iより後ろが全部消えているときの最小回数とする。すると遷移は
if(i番目の状態が0)
dp[i][0]=dp[i-1][0];
dp[i][1]=dp[i-1][1]+1(i番目を消す)+{(2i)-1}(i-1番目を消す)
else
dp[i][1]=dp[i-1][0];
dp[i][0]=dp[i-1][1]+1+{(2i)-1}(上と同様)
で、実装できる。
n<=50に騙されてどうしようかわからず公式解説よんだ・・・

LL dp[60][2];
string str;
int main() {
    cin >> str;
    reverse(str.begin(), str.end());
    dp[0][str[0]-'0'] = 0;
    dp[0][1-(str[0]-'0')] = 1;
    for (int i = 1; i < n; i++) {
        if (str[i]-'0') {
            dp[i][0] = dp[i-1][1] + 1 + pow(2, i) - 1;
            dp[i][1] = dp[i-1][0];
        }
        else {
            dp[i][1] = dp[i-1][1] + 1 + pow(2, i) - 1;
            dp[i][0] = dp[i-1][0];
        }
    }
    cout << dp[n-1][0] << endl;
    return 0;
}