DPする。
dp[どこまで見た][閉じていない開き括弧の数][これまでの和]
+ に括弧を付けても意味がないので、- のところに括弧を付ける。
- ( ... - ( ... - ( ) ... ) ... - ( ) ... ) みたいになるとして、
閉じられていない括弧の数が偶数か奇数かどうかで、今見ている数の符号が反転するかどうか分かる。
#include <algorithm>
#include <iostream>
#include <sstream>
#include <set>
using namespace std;
const int N = 35;
const int M = (3000 + 1) * 2;
int size;
int num[N];
char op[N];
bool dp[N][N][M];
int main(int argc, char *argv[])
{
for (string s; getline(cin, s); ) {
istringstream iss(s);
for (iss >> num[size = 0]; iss >> op[size++]; iss >> num[size]) ;
op[size - 1] = '=';
fill(&dp[0][0][0], &dp[N - 1][N - 1][M], false);
dp[1][0][num[0] + 3000] = true;
for (int i = 1; i < (int)size; ++i) {
for (int j = 0; j < (int)size; ++j) {
for (int k = 0; k < (int)M; ++k) {
if (!dp[i][j][k]) continue;
int l = k + ((j + (op[i - 1] == '-')) % 2 ? -1 : +1) * num[i];
dp[i + 1][j][l] = true;
if (j) {
dp[i + 1][j - 1][l] = true;
}
if (op[i - 1] == '-') {
int l = k + ((j + 1) % 2 ? -1 : +1) * num[i];
dp[i + 1][j + 1][l] = true;
}
}
}
}
set<int> res;
for (int i = 0; i < (int)N; ++i) {
for (int j = 0; j < (int)M; ++j) {
if (dp[size][i][j]) res.insert(j - 3000);
}
}
cout << res.size() << endl;
}
return 0;
}