#include <iostream> #include <string> #include <vector> #include <map> #include <set> #include <algorithm> using namespace std; // implementation of suffix array construction based on skew algorithm struct Index { typedef unsigned long long Int; static const Int MAX = 200000; //------------------------------------------------------------------- // zero-free out_of_range-torrerent arrays //------------------------------------------------------------------- struct Array : vector<Int> { Int& operator[](size_t i) { return vector<Int>::operator[](i); } const Int operator[](size_t i) const { return size()<=i ? 0 : vector<Int>::operator[](i); } }; //------------------------------------------------------------------- // [cab] ==> [312] : "cab$ is the 3rd suffix", "ab$ is the 1st" ... //------------------------------------------------------------------- static void suffix_ranking( const Array& v, Array* pResult ) { pResult->resize( v.size() ); Array sary; suffix_array( v, &sary ); for(size_t i=0; i!=sary.size(); ++i) (*pResult)[sary[i]-1] = i+1; #ifdef EBUG cerr<< "v : "; for(size_t i=0; i!=v.size(); ++i) cerr << v[i] << " "; cerr << endl; cerr<< "sary: "; for(size_t i=0; i!=v.size(); ++i) cerr << sary[i] << " "; cerr << endl; cerr<< "rank: "; for(size_t i=0; i!=v.size(); ++i) cerr << (*pResult)[i] << " "; cerr << endl; #endif } //------------------------------------------------------------------- // [cab] ==> [231] : "suffix at pos2 (ab$) is the first suffix", ... //------------------------------------------------------------------- static void suffix_array( const Array& v, Array* pResult ) { pResult->resize( v.size(), 1 ); // Small cases if( v.size() <= 1 ) {return;} if( v.size() == 2 ) {(*pResult)[(v[0]>=v[1] ? 0 : 1)] = 2; return;} // STEP1 // make mod1/mod2 triples and recursively their suffix ranks Array triple_rank; { map<Int,Int> idx; { set<Int> triples; for(size_t i=1; i<=v.size(); i+=3) triples.insert( v[i]*MAX*MAX+v[i+1]*MAX+v[i+2] ); for(size_t i=2; i<v.size(); i+=3) triples.insert( v[i]*MAX*MAX+v[i+1]*MAX+v[i+2] ); Int r = 0; for(set<Int>::iterator it=triples.begin(); it!=triples.end(); ++it) idx[*it] = ++r; } Array triple_array; { for(size_t i=1; i<=v.size(); i+=3) triple_array.push_back( idx[v[i]*MAX*MAX+v[i+1]*MAX+v[i+2]] ); for(size_t i=2; i<v.size(); i+=3) triple_array.push_back( idx[v[i]*MAX*MAX+v[i+1]*MAX+v[i+2]] ); } suffix_ranking( triple_array, &triple_rank ); #ifdef EBUG for(size_t i=0; i!=triple_rank.size(); ++i) cerr << triple_array[i] << " "; cerr << endl; for(size_t i=0; i!=triple_rank.size(); ++i) cerr << triple_rank[i] << " "; cerr << endl; #endif } // STEP2,3 // sort all suffices for(size_t i=0; i!=v.size(); ++i) (*pResult)[i] = i+1; sort( pResult->begin(), pResult->end(), cmp(&v, &triple_rank) ); } struct cmp { const Array *pv, *ptr; cmp( const Array* pv, const Array* ptr ) : pv(pv), ptr(ptr) {} Int v(Int i) const {return (*pv)[i];} Int tr(Int i) const {return (*ptr)[i%3==1 ? i/3 : (pv->size()+2)/3+i/3];} bool operator()( Int i, Int j ) const { --i, --j; if( v(i)!=v(j) ) return v(i) < v(j); if( v(i+1)!=v(j+1) ) return v(i+1) < v(j+1); if( i%3!=0 && j%3!=0 ) return tr(i) < tr(j); // 11, 12, 21, 22 if( i%3!=2 && j%3!=2 ) return tr(i+1) < tr(j+1); // 00, 01, 10 return tr(i+2) < tr(j+2); // 02, 20 } }; //------------------------------------------------------------------- // MAIN //------------------------------------------------------------------- Index( const char* p, int N ) { Array v, sary0; for(size_t i=0; i!=N; ++i) v.push_back( (unsigned char)(p[i]) ); suffix_array( v, &sary0 ); for(size_t i=0; i!=N; ++i) sary.push_back( p+sary0[i]-1 ); #ifdef EBUG for(int i=0; i!=sary.size(); ++i) cerr << sary[i] << "$" << endl; #endif } int count( string& q ) { vector<const char*>::iterator b = lower_bound( sary.begin(), sary.end(), q.c_str(), str_cmp() ); q[q.size()-1]++; vector<const char*>::iterator e = lower_bound( b, sary.end(), q.c_str(), str_cmp() ); return e-b; } struct str_cmp { bool operator()( const char* p, const char* q ) const { return strcmp(p,q)<0; }}; vector<const char*> sary; }; int main() { int N=0; for(string str; getline(cin,str);) { if(N++) cout << endl; cout << "Case " << N << ":" << endl; // reference text string text; while( getline(cin,str), str!="%%%%%" ) text+=str, text+=" "; // indexing Index idx(text.c_str(), text.size()); // query while( getline(cin,str), str!="%%%%%" ) cout << idx.count(str) << endl; getline(cin,str); } }