これは自分で解けなかったので、解説を見て解いてみた。
http://utpc2012.contest.atcoder.jp/tasks/utpc2012_06
簡単なハッシュ計算式が与えられ、同じハッシュ値の文字列を100個生成する。
最初、決定的な手法で同じ文字列を作れるかと思ったけど、文字列長の最大値が50と小さいので無理だった。
このハッシュ値は最大10^9程度。アルファベットが7文字だと26^7≒8*10^9なので、7文字あれば同じハッシュ値の文字列が8つずつある。
また、このハッシュ関数では、ハッシュ値Aの文字列とハッシュ値Bの文字列を合わせた文字列のハッシュ値は、元の2つの文字列にかかわらずそのハッシュ値は一致する。
よって、ランダム探索で同じハッシュ値が2個ある文字列を7組見つけ、その7組から1つずつ文字列を取り出して連結すれば、2^7=128通りの49文字の文字列が作れる。
ll A,B; map<int, vector<string> > poem; int nc; int cand[7]; void solve() { int x,y,i,j,rr,TM,nc; int tx,ty; ll p; char str[8]; A=GETi(); B=GETi(); poem.clear(); srand(time(NULL)); p=0;nc=0;str[7]=0; while(nc<7){ ll hash=0; string st; p++; FOR(i,7) { str[i]='a'+rand()%26; hash = (hash*A+(str[i]+1-'a')) % B; } st = string(str); if(poem[(int)hash].size()==0) { poem[(int)hash].push_back(st); } else if(poem[(int)hash].size()==1 && poem[(int)hash][0]!=st) { poem[(int)hash].push_back(st); cand[nc++]=(int)hash; } } FOR(i,100) { string st=""; FOR(j,7) st += poem[cand[j]][(i>>j)&1]; _P("%s\n",st.c_str()); } return; }
まとめ
こんなところでランダム探索が出てきたか…。
誕生日パラドックスはO(√N)程度でハッシュ値が衝突するペアを探せるんだな、覚えておこう。