GCJ 2015 Round 1C B. Typewriter Monkey
問題
$K$ 文字のアルファベット (重複があり得る) からなるキーボードがある. この中から一様ランダムに $S$ 回叩いて,長さ $L$ の目標の文字列を入力したい. 入力された文字列に含まれる,目標の文字列の数の期待値を求めなさい.
方針
Small は全探索する.Large は 「$dp(i,j,k) $ $=$ $i$ 文字目まで打ったときに,過去に $k$ 回最後まで一致していて,今は $j$ 文字目まで一致している確率」とかおいて解くんだと思う…
実装
namespace small {
int cnt(string have, string target){
int res = 0;
rep(i,have.size()-target.size()+1){
if(have.substr(i,target.size())==target) res++;
}
return res;
}
double solve(string keys, string target, int S){
ll pat = 1;
rep(i,S) pat *= keys.size();
ll mx = 0, sum = 0;
rep(mask,pat){
string r(S,' ');
int t = mask;
rep(i,S){
r[i] = keys[t%keys.size()];
t/=keys.size();
}
ll c = cnt(r,target);
sum += c;
mx = max(mx,c);
}
return (double)mx-(double)sum/pat;
}
}
namespace large {
// あとで解く
}
signed main(){
ios_base::sync_with_stdio(0); cin.tie(0);
signed T;
cin >> T;
rep(i,T){
int K,L,S;
cin >> K >> L >> S;
string keys; cin >> keys;
string target; cin >> target;
// double ans_small = small::solve(keys, target, S);
double ans_large = large::solve(keys, target, S);
// printf("Case #%d: %lf\n",(int)i+1,ans_small);
printf("Case #%d: %lf\n",(int)i+1,ans_large);
}
}