Link : PLD
Category : Hashing
Hint : Consider substrings of S of length k and substrings of Reverse(S) of length k. If the hash value of one substring of S matches with hash value of substring of Reverse(S), and second starts when first ends, there is a match!
Solution : Well, the hint says pretty much all of it, except for a good hash function. For hash value of substring Si to Sj, we better not take O(k) time (else program is O(N*K) and gets TLE), hence I used the polynomial hash function
Hash({Si to Sj})=(Sia0+Si+1a1+Si+2a2...)%p
Where a and p were primes (p was because of good hash spread, a was for no good reason :D ). This hash function allows Hash({Si to Sj}) to be computed from Hash({Si-1 to Sj-1}) in O(1) time, giving the complexity of hashing all substrings of S of length k O(N).
To do the index match (S's substring ends where Reverse(S)'s starts), keep a sorted vector at all hash values, and so a binary search.
Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cstring> | |
#include <cmath> | |
#include <algorithm> | |
#include <vector> | |
#include <list> | |
#include <queue> | |
#include <stack> | |
#include <map> | |
#include <set> | |
#include <utility> | |
#include <climits> | |
#include <cfloat> | |
#include <cassert> | |
#define readint(n) scanf("%d",&n) | |
#define readull(n) scanf("%llu",&n) | |
#define readll(n) scanf("%lld",&n) | |
#define readf(n) scanf("%f",&n) | |
#define readd(n) scanf("%lf",&n) | |
#define init(mem) memset(mem,0,sizeof(mem)) | |
#define ll long long int | |
#define ull unsigned long long int | |
using namespace std; | |
#define HASHFAC 137 | |
#define MOD 1000003 | |
ll pow_log(ll base,ll exp){ | |
if(exp==0) return 1; | |
else if(exp==1) return base; | |
else if(exp%2==0){ | |
ll val=pow_log(base,exp/2); | |
return (val*val)%MOD; | |
} | |
else{ | |
return (base*pow_log(base,exp-1))%MOD; | |
} | |
} | |
bool binSearch(vector<int> *v,int val,int l,int h){ | |
if(h-l<=1){ | |
if((*v)[l]==val || (*v)[h]==val) return true; | |
return false; | |
} | |
int m=(h+l)/2; | |
if((*v)[m]==val) return true; | |
else if((*v)[m]>val) return binSearch(v,val,l,m); | |
return binSearch(v,val,m,h); | |
} | |
bool has(vector<int> *v,int val){ | |
if(v->size()==0 or (*v)[0]>val or (*v)[v->size()-1]<val) return false; | |
return binSearch(v,val,0,v->size()-1); | |
} | |
int main(){ | |
int k,n; | |
string str; | |
readint(k); | |
cin>>str; | |
n=str.length(); | |
ll divfactor=pow_log(HASHFAC,MOD-2); | |
ll multfactor=pow_log(HASHFAC,k-1); | |
vector<int>* v=new vector<int>[MOD]; | |
// hash first k values | |
ll hashval=0; | |
ll fac=1; | |
for(int i=0;i<k;i++){ | |
hashval=(hashval+fac*(str[i]-'a'))%MOD; | |
fac=(fac*HASHFAC)%MOD; | |
} | |
v[hashval].push_back(k-1); | |
#ifdef db | |
cout<<hashval<<endl; | |
#endif | |
for(int i=k;i<n;i++){ | |
hashval=(hashval+MOD-(str[i-k]-'a'))%MOD;; | |
hashval=(hashval*divfactor)%MOD; | |
hashval=(hashval+(str[i]-'a')*multfactor)%MOD; | |
v[hashval].push_back(i); | |
#ifdef db | |
cout<<hashval<<endl; | |
#endif | |
} | |
int count=0; | |
hashval=0; | |
fac=1; | |
for(int i=n-1;i>=n-k;i--){ | |
hashval=(hashval+fac*(str[i]-'a'))%MOD; | |
fac=(fac*HASHFAC)%MOD; | |
} | |
if(has(&v[hashval],n-1)){ | |
count++; | |
} | |
for(int i=n-k-1;i>=0;i--){ | |
hashval=(hashval+MOD-(str[i+k]-'a'))%MOD;; | |
hashval=(hashval*divfactor)%MOD; | |
hashval=(hashval+(str[i]-'a')*multfactor)%MOD; | |
if(has(&v[hashval],i+k-1)){ | |
count++; | |
} | |
} | |
printf("%d\n",count); | |
return 0; | |
} |