Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <iostream>
- #include <vector>
- #include <map>
- using namespace std;
- typedef long long int64;
- const int kSigma = 27;
- struct RollingHash {
- static const int kMods[];
- static const int kNumMods = 2;
- int normal[kNumMods]; // left to right
- int reversed[kNumMods]; // right to left
- int sig_exp[kNumMods];
- RollingHash() {
- for (int i = 0; i < kNumMods; i += 1) {
- normal[i] = reversed[i] = 0;
- sig_exp[i] = 1;
- }
- }
- void AddLeft(char c) {
- for (int i = 0; i < kNumMods; i += 1) {
- int kMod = kMods[i];
- reversed[i] = (1LL * reversed[i] * kSigma + c - 'a' + 1) % kMod;
- normal[i] = (normal[i] + 1LL * sig_exp[i] * (c - 'a' + 1)) % kMod;
- sig_exp[i] = (1LL * sig_exp[i] * kSigma) % kMod;
- }
- }
- void AddRight(char c) {
- for (int i = 0; i < kNumMods; i += 1) {
- int kMod = kMods[i];
- normal[i] = (1LL * normal[i] * kSigma + c - 'a' + 1) % kMod;
- reversed[i] = (reversed[i] + 1LL * sig_exp[i] * (c - 'a' + 1)) % kMod;
- sig_exp[i] = (1LL * sig_exp[i] * kSigma) % kMod;
- }
- }
- RollingHash ReverseHash() {
- RollingHash r = *this;
- for (int i = 0; i < kNumMods; i += 1) {
- swap(r.normal[i], r.reversed[i]);
- }
- return r;
- }
- bool IsPalindrome() {
- bool ok = true;
- for (int i = 0; i < kNumMods; i += 1) {
- ok &= normal[i] == reversed[i];
- }
- return ok;
- }
- bool operator<(const RollingHash& rhs) const {
- for (int i = 0; i < kNumMods; i += 1) {
- if (rhs.normal[i] != normal[i]) {
- return normal[i] < rhs.normal[i];
- }
- }
- return false;
- }
- };
- const int RollingHash::kMods[] = {(int)1e9+7, (int)1e9+9};
- map<RollingHash, int> palindroms_from_here, reversed_full_word;
- int main() {
- int n; cin >> n;
- vector<string> all_words(n);
- for (int i = 0; i < n; i += 1) {
- cin >> all_words[i];
- }
- for (const string& word : all_words) {
- int l = (int)word.size();
- vector<bool> is_poli(l + 1, false);
- {
- RollingHash a;
- for (int i = l; i >= 0; i -= 1) {
- if (a.IsPalindrome()) {
- is_poli[i] = true;
- }
- if (i != 0) {
- a.AddLeft(word[i - 1]);
- }
- }
- }
- vector<RollingHash> left_reversed_hash;
- {
- RollingHash b;
- for (int i = 0; i <= l; i += 1) {
- left_reversed_hash.push_back(b.ReverseHash());
- if (i != l) {
- b.AddRight(word[i]);
- }
- }
- reversed_full_word[b.ReverseHash()] += 1;
- }
- for (int i = 0; i <= l; i += 1) {
- if (is_poli[i]) {
- palindroms_from_here[left_reversed_hash[i]]+= 1;
- }
- }
- }
- int64 result = 0;
- for (auto word : all_words) {
- RollingHash a, b;
- vector<RollingHash> front(word.size() + 1);
- vector<RollingHash> back(word.size() + 1);
- for (int i = 0; i <= (int)word.size(); i += 1) {
- front[i] = a;
- if (i != (int)word.size()) {
- a.AddRight(word[i]);
- }
- }
- for (int i = (int)word.size(); i >= 0; i -= 1) {
- back[i] = b;
- if (i != 0) {
- b.AddLeft(word[i - 1]);
- }
- }
- for (int i = 0; i <= (int)word.size(); i += 1) {
- if (front[i].IsPalindrome()) {
- result += reversed_full_word[back[i]];
- }
- }
- result -= reversed_full_word[a]; // equal words
- result += palindroms_from_here[a]; // our word is on the right without having the big part
- if (a.IsPalindrome()) {
- result -= 1;
- }
- }
- cout << result << '\n';
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement