/**
* Calculate the number of occurances of ALL permutations of a given word in a given text.
* INPUT:
* |word| |text|
* word
* text
* OUTPUT:
* The number of times "word" or any permutation of it appears in "text".
* ALGORITHM:
* - Create a multiset of letters in "word".
* - Go over "text", and check if any letter appears in the multiset.
*
* @author Erel Segal
* @date 2010-11-04
*/
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
typedef unsigned short ushort;
typedef unsigned int uint;
// A multiset of letters - counts how many times each letter appears:
class EnglishLettersMultiset {
ushort caps[26], noncaps[26];
ushort myCount;
public:
EnglishLettersMultiset() {
fill_n(caps,26, (ushort)0);
fill_n(noncaps,26, (ushort)0);
myCount = 0;
}
EnglishLettersMultiset& operator= (const EnglishLettersMultiset& other) {
copy(other.caps,other.caps+26, caps);
copy(other.noncaps,other.noncaps+26, noncaps);
myCount = other.myCount;
return *this;
}
// Increase the counter for a single letter:
void add(char c) {
if ('A'<=c && c<='Z') {
caps[c-'A']++;
myCount++;
} else if ('a'<=c && c<='z') {
noncaps[c-'a']++;
myCount++;
} else throw string("tried to add an illegal char '")+c+string("'");
}
// Decrease the counter for a single letter; returns true iff it exists.
bool testAndRemove(char c) {
if ('A'<=c && c<='Z') {
if (caps[c-'A']>0) {
caps[c-'A']--;
myCount--;
return true;
} else return false;
} else if ('a'<=c && c<='z') {
if (noncaps[c-'a']>0) {
noncaps[c-'a']--;
myCount--;
return true;
} else return false;
} else throw string("tried to remove an illegal char '")+c+string("'");
}
bool count() const { return myCount; }
bool empty() const { return myCount==0; }
}; // class EnglishLettersMultiset
uint countPermutations(const string& word, const string& text) {
// Initialization: create a multiset of letters in word
EnglishLettersMultiset wordLetters;
string::const_iterator cWord, cText;
for (cWord=word.begin(); cWord!=word.end(); ++cWord)
wordLetters.add(*cWord);
uint count=0;
EnglishLettersMultiset tempWordLetters=wordLetters;
bool changed=true;
for (cText=text.begin(); cText!=text.end(); ++cText) {
//cout << *cText << ":";
if (changed) {
tempWordLetters = wordLetters; // restore the temporary multiset for the next iteration
changed=false;
}
for (cWord=cText; cWord!=text.end(); ++cWord) {
//cout << *cWord;
if (!tempWordLetters.testAndRemove(*cWord)) { // no permutation starts at cText
//cout << "-";
break;
} else {
changed = true;
if (tempWordLetters.empty()) { // found a permutation
//cout << "+";
count++;
break;
}
}
}
// cout << " ";
}
return count;
}
void assertCount(string word, string text, uint expected) {
time_t before = time(NULL);
uint a = countPermutations(word,text);
if (a!=expected) {
cerr << "ERROR: Count of " << word << " in " << text << " should be " << expected << " but was " << a << endl;
} else {
time_t after = time(NULL);
cout << "calculated cost of " << word.length() << "x" << text.size() << " chars in " << (after-before) << " seconds" << endl;
}
}
void testIdentical(int N) {
string word1(1, 'a');
string word2(2, 'a');
string text(N, 'a');
assertCount(word1, text, N);
assertCount(word2, text, N-1);
assertCount(text, word1, 0);
assertCount(text, word2, 0);
}
void testAlmostIdentical(int N) {
string word("ab");
string text(N, 'a'); text += 'b';
assertCount(word, text, 1);
}
int main() {
try {
/* tests:
assertCount("cAda","AbrAcadAbRa",2);
testIdentical(13);
testAlmostIdentical(13);
*/
uint nWord, nText;
cin >> nWord >> nText;
string word, text;
cin >> word >> text;
cout << countPermutations(word,text) << endl;
} catch (string message) {
cerr << "ERROR: " << message << endl;
}
}