http://community.topcoder.com/stat?c=problem_statement&pm=11634&rd=14553
memo[一方をどこまで作った][もう一方をどこまで作った]
s[x[k]] = s[y[k]] の条件を満たしうる長さN/2の文字列を全て生成して数え上げる。
候補の文字列をtとして、memo[i][j]に注目している時、t[i]かt[j]のどちらかに文字を割り当てる。
割り当てられる文字はs[i + j]。
(2^20)*(20^2)は無理だろうと思ってひたすら別解法を考えたけど、結局はこれだった。
あまり手を抜くとTLEする。
const int M = 40; lli memo[M][M]; lli rec(int i, int j, const string& s, const string& t) { if (i == t.size() && j == t.size()) return 1; if (t.size() < i || t.size() < j) return 0; lli& ret = memo[i][j]; if (ret != -1) return ret; lli sum = 0; const int k = i + j; if (s[k] == t[i]) sum += rec(i + 1, j, s, t); if (s[k] == t[j]) sum += rec(i, j + 1, s, t); return ret = sum; } class SPartition { public: long long getCount(string s) { if (count(s.begin(), s.end(), 'o') % 2) return 0; if (count(s.begin(), s.end(), 'x') % 2) return 0; const int x = count(s.begin(), s.end(), 'x'); vector<string> v; const int N = s.size() / 2; const int BIT = 1 << N; for (int bit = 0; bit < BIT; ++bit) { if (__builtin_popcount(bit) != x / 2) continue; string t; for (int i = 0; i < N; ++i) { t += (bit & (1 << i)) ? 'x' : 'o'; } v.push_back(t); } lli sum = 0; for (int i = 0; i < v.size(); ++i) { fill(&memo[0][0], &memo[M - 1][M - 1] + 1, -1); sum += rec(0, 0, s, v[i]); } return sum; } };