SRM 327 Div1 Easy / Div 2 Hard NiceOrUgly
問題
アルファベットもしくは'?'からなる文字列が与えられる。
母音字が3つ以上連続で、もしくは子音字が5つ以上連続で並ぶ、のどちらかの条件を満たすような文字列をUGLYであるという。そうでない文字列をNICEであるという。
'?'にどのような文字を入れても文字列がUGLYになるならUGLYを、どのような文字を入れてもNICEになるならNICEを、どちらにもできるなら42を返せ。
制約条件
文字列の長さ≦50
方針
探索するのか?とか思ったらDPでいけるらしい。
TopCoderの探索は大抵DPに落とせる←教訓
文字列をuglyにできるかどうかは簡単に判定できる。
niceにできるかは、dp[i][j][k]に、i文字までで、母音字がj文字連続していて、子音字がk文字連続している(今のところniceな)文字列があるかどうかをもっておき、更新してくようなdpによりできる。
dp[n][i][j]で1になるようなものがあればniceにできるという訳。
ソースコード
int n,dp[51][3][5]; bool vow(char c){ return c=='A'||c=='E'||c=='I'||c=='O'||c=='U'; } class NiceOrUgly { public: string describe(string s) { n=s.size(); bool ugly=0,nice=0; rep(i,n-2){ bool ok=1; rep(j,3)if(s[i+j]!='?'&&!vow(s[i+j]))ok=0; ugly|=ok; } rep(i,n-4){ bool ok=1; rep(j,5)if(vow(s[i+j]))ok=0; ugly|=ok; } rep(i,n+1)rep(j,3)rep(k,5)dp[i][j][k]=0; dp[0][0][0]=1; rep(i,n)rep(j,3)rep(k,5)if(dp[i][j][k]){ if(j<2&&(s[i]=='?'||vow(s[i])))dp[i+1][j+1][0]=1; if(k<4&&(!vow(s[i])))dp[i+1][0][k+1]=1; } rep(j,3)rep(k,5)nice|=dp[n][j][k]; if(!ugly)return "NICE"; return nice?"42":"UGLY"; } };