TTPC2015 G titech分離
問題
方針
下のようなオートマトンを $|S|/6$ 個考える.
“$dp[t_1][i][t_2][e][c][h][pos] = $ $S[pos]$ まで見たときにそれぞれの状態にあるオートマトンの数としてありえるか?” とおいてメモ化再帰で埋める. $pos = |S|$ のときに全て受理状態になっていれば OK.
図は http://madebyevan.com/fsm/ で描きました.
実装
int n;
string s;
char dp[18][18][18][18][18][18];
bool rec(int t1, int i, int t2, int e, int c, int h, int pos){
char & res = dp[t1][i][t2][e][c][h];
if(res != -1){
return res;
} else if(pos == n){
return (res = t1 + i + t2 + e + c + h == 0);
} else if(s[pos] == 't'){
return (res = (t1 != 0 && rec(t1-1,i+1,t2,e,c,h,pos+1)) || (t2 != 0 && rec(t1,i,t2-1,e+1,c,h,pos+1)));
} else if(s[pos] == 'i'){
return (res = i != 0 && rec(t1, i-1, t2+1, e, c, h, pos+1));
} else if(s[pos] == 'e'){
return (res = e != 0 && rec(t1, i, t2, e-1, c+1, h, pos+1));
} else if(s[pos] == 'c'){
return (res = c != 0 && rec(t1, i, t2, e, c-1, h+1, pos+1));
} else if(s[pos] == 'h'){
return (res = h != 0 && rec(t1, i, t2, e, c, h-1, pos+1));
}
return -10;
}
bool solve(){
n = s.size();
if(n%6 != 0) return false;
map<char,int> cnt;
for(char c : s) cnt[c]++;
if(cnt['t'] != n/6*2) return false;
if(cnt['i'] != n/6) return false;
if(cnt['e'] != n/6) return false;
if(cnt['c'] != n/6) return false;
if(cnt['h'] != n/6) return false;
mems(dp,-1);
return rec(n/6,0,0,0,0,0,0);
}
signed main(){
while(cin >> s) puts(solve() ? "Yes" : "No");
}
こういう系の問題はコンテスト中に解けた試しがない.