Problem 1203 : Napoleon's Grumble
問題概要
与えられた文字列に含まれる長さ3以上の回文を全て出力せよ。
ただし、他の回文の中央に完全に含まれるような回文は出力しない。
回文はどのような順番で出力してもよい。
また、元の文字列のアルファベット以外の文字は無視し、回文は英大文字で、スペース区切りで出力する。
解法
回文の全列挙はrolling hashを使ってO(n^2)でできる。
(過去に何度か解説書いたので参照)
回文が他の回文の中央に入っているかはナイーブに回文を全部調べても0msで通ったが、もう少し効率的にもできる。
(文字数の偶奇で分けて、一文字、二文字、三文字…の部分文字列を全てsetに入れる)
ソースコード
int main() { string t; int n; while(getline(cin,t)){ string s; fr(i,t)if(isalpha(*i))s.pb(toupper(*i)); n=s.size(); set<string> S; rep(i,n-2){ ll h=0,H=0,b=1; int j=i; rep(k,2){ h*=29; h+=s[j]-'A'; H+=b*(s[j]-'A'); b*=29; j++; } for(;j<n;j++){ h*=29; h+=s[j]-'A'; H+=b*(s[j]-'A'); b*=29; if(h==H)S.insert(s.substr(i,j-i+1)); } } vs v; fr(i,S)v.pb(*i); int m=v.size(); bool f=1; vector<int> len; rep(i,m)len.pb(v[i].size()); rep(i,m){ rep(j,m)if(i!=j){ if(len[i]<len[j]&&v[i]==v[j].substr((len[j]-len[i])/2,len[i]))goto FAIL; } if(!f)cout<<" "; else f=0; cout<<v[i]; FAIL:; } cout<<endl; } return 0; }