题意:

题目链接

给出\(n\)个字符串,求有多少对\((i,j),i \neq j\)使得\(s_i\)与\(s_j\)拼起来是回文串

分析:

设\(s_i,s_j\)的长度分别为\(L_i, L_j\),一共有如下三种情况:

  • \(L_i=L_j\),那么有\(s_i\)等于\(s_j\)的反串,\(s_i,s_j\)构成回文串,注意\(s_i\)本身是回文串的情况,需要从答案中减去
  • \(L_i > L_j\),那么有\(s_i\)的某个后缀是回文串,并且\(s_j\)是剩余部分的反串
  • \(L_i < L_j\),分析方法同上

用两个map<hash, int>分别来记录正串和反串的\(hash\)值

并且预处理所有字符串的前缀后缀的正串反串的\(hash\)值,这样就可以\(O(1)\)判断某个前缀后缀是否为回文串

第一种情况直接计数,对于后两种情况每次枚举较长串的回文前缀和后缀即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
using namespace std;
#define REP(i, a, b) for(int i = a; i < b; i++)
#define PER(i, a, b) for(int i = b - 1; i >= a; i--) typedef long long LL; const int maxn = 100000 + 10;
const int MOD[2] = { 1000000007, 1000000009 }; int n; struct Hash {
int h[2];
Hash(int h0 = 0, int h1 = 0) { h[0] = h0; h[1] = h1; }
Hash(char c) { h[0] = c-'a'+1; h[1] = c-'a'+1; }
bool operator < (const Hash& t) const {
return h[0] < t.h[0] || (h[0] == t.h[0] && h[1] < t.h[1]);
}
Hash operator * (const Hash& t) const {
return Hash(1LL * t.h[0] * h[0] % MOD[0], 1LL * t.h[1] * h[1] % MOD[1]);
}
Hash operator + (const Hash& t) const {
return Hash((h[0] + t.h[0]) % MOD[0], (h[1] + t.h[1]) % MOD[1]);
}
bool operator == (const Hash& t) const {
return h[0] == t.h[0] && h[1] == t.h[1];
}
void debug() { printf("{ %d, %d }\n", h[0], h[1]); }
}; Hash p(1, 1);
const Hash base(27, 27); Hash addLeft(const Hash& a, char c) {
return (Hash(c) * p) + a;
} Hash addRight(const Hash& a, char c) {
return (a * base) + Hash(c);
} vector<string> s;
map<Hash, int> Normal, Reverse;
vector<Hash> preNormal[maxn], preReverse[maxn], sufNormal[maxn], sufReverse[maxn]; int main() {
scanf("%d", &n); s.resize(n);
REP(i, 0, n) {
cin >> s[i];
int l = s[i].length(); p = Hash(1, 1);
preNormal[i].emplace_back(0, 0);
preReverse[i].emplace_back(0, 0);
REP(j, 0, l) {
preNormal[i].push_back(addRight(preNormal[i][j], s[i][j]));
preReverse[i].push_back(addLeft(preReverse[i][j], s[i][j]));
p = p * base;
} p = Hash(1, 1);
sufNormal[i].resize(l + 1);
sufReverse[i].resize(l + 1);
sufNormal[i][l] = sufReverse[i][l] = Hash(0, 0);
PER(j, 0, l) {
sufNormal[i][j] = addLeft(sufNormal[i][j+1], s[i][j]);
sufReverse[i][j] = addRight(sufReverse[i][j+1], s[i][j]);
p = p * base;
}
Normal[preNormal[i][l]]++;
Reverse[preReverse[i][l]]++;
} LL ans = 0;
REP(i, 0, n) {
int l = s[i].length(); //case 1
if(Reverse.count(preNormal[i][l]))
ans += Reverse[preNormal[i][l]];
if(preNormal[i][l] == preReverse[i][l]) ans--; //case 2
PER(j, 1, l) if(sufNormal[i][j] == sufReverse[i][j]) {
if(Reverse.count(preNormal[i][j]))
ans += Reverse[preNormal[i][j]];
} //case 3
REP(j, 1, l) if(preNormal[i][j] == preReverse[i][j]) {
if(Normal.count(sufReverse[i][j]))
ans += Normal[sufReverse[i][j]];
}
} cout << ans << endl; return 0;
}

CSAcademy Palindromic Concatenation 字符串哈希的更多相关文章

  1. HDU 1880 魔咒词典(字符串哈希)

    题目链接 Problem Description 哈利波特在魔法学校的必修课之一就是学习魔咒.据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一 ...

  2. 洛谷P3370 【模板】字符串哈希

    P3370 [模板]字符串哈希 143通过 483提交 题目提供者HansBug 标签 难度普及- 提交  讨论  题解 最新讨论 看不出来,这题哪里是哈希了- 题目描述 如题,给定N个字符串(第i个 ...

  3. HDU2594 Simpsons’ Hidden Talents 字符串哈希

    最近在学习字符串的知识,在字符串上我跟大一的时候是没什么区别的,所以恶补了很多基础的算法,今天补了一下字符串哈希,看的是大一新生的课件学的,以前觉得字符串哈希无非就是跟普通的哈希没什么区别,倒也没觉得 ...

  4. LA 6047 Perfect Matching 字符串哈希

    一开始我用的Trie+计数,但是不是计多了就是计少了,后来暴力暴过去的…… 看了别人的代码知道是字符串哈希,但是仍有几个地方不理解: 1.26^500溢出问题 2.没考虑哈希碰撞? 跪求指点! #in ...

  5. AC日记——【模板】字符串哈希 洛谷 3370

    题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...

  6. 从Hash Killer I、II、III论字符串哈希

    首先,Hash Killer I.II.III是BZOJ上面三道很经典的字符串哈希破解题.当时关于II,本人还琢磨了好久,但一直不明白为啥别人AC的代码都才0.3kb左右,直到CYG神犇说可以直接随机 ...

  7. 【NOIP模拟】Grid(字符串哈希)

    题目背景 SOURCE:NOIP2016-RZZ-1 T3 题目描述 有一个 2×N 的矩阵,矩阵的每个位置上都是一个英文小写字符. 现在需要从某一个位置开始,每次可以移动到一个没有到过的相邻位置,即 ...

  8. 洛谷 P3370 【模板】字符串哈希

    洛谷 P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的 ...

  9. cf_514C(字符串哈希)

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121897#problem/G Watto and Mechanism Time ...

随机推荐

  1. 变更hostname

    具有dns解析的主机名 # vim /etc/sysconfig/network ... HOSTNAME=webserver.mydomain.com ... # hostname webserve ...

  2. Linux学习_按时间顺序解压多个文件,搜索文件中的内容

    ls的结果按时间数据先排序,再取末尾5个文件,再调用tar命令 ls -1 | sort -u | tail -5 |xargs -n1 tar xzvf 利用grep命令从文件中搜索. grep - ...

  3. nginx处理HTTP header问题

    在实际开发中遇到http header 自定义key中包含下划线(_)时服务端header丢失的问题,解决办法详细见以下网页内容,感谢原博主 http://blog.csdn.net/dac55300 ...

  4. 笨办法学Python(三十七)

    习题 37: 复习各种符号 现在该复习你学过的符号和 python 关键字了,而且你在本节还会学到一些新的东西.我在这里所作的是将所有的 Python 符号和关键字列出来,这些都是值得掌握的重点. 在 ...

  5. 笨办法学Python(二十九)

    习题 29: 如果(if) 下面是你要写的作业,这段向你介绍了“if语句”.把这段输入进去,让它能正确执行.然后我们看看你是否有所收获. people = 20 cats = 30 dogs = 15 ...

  6. 365. Water and Jug Problem (GCD or BFS) TBC

    https://leetcode.com/problems/water-and-jug-problem/description/ -- 365 There are two methods to sol ...

  7. 实例详解Django的 select_related

    在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子详解这两个函数的作用.虽然Q ...

  8. Codeforces 758D Ability To Convert(区间DP)

    题目链接:http://codeforces.com/problemset/problem/758/D 题意:一个n进制下的数k,其中k不会用字母,如果有A就用10代替了.求k这个数对应的,在10进制 ...

  9. 最长公共单词,类似LCS,(POJ2250)

    题目链接:http://poj.org/problem?id=2250 解题报告: 1.状态转移方程: ; i<=len1; i++) { ; j<=len2; j++) { dp[i][ ...

  10. 解方程求PH值,POJ(2006)

    题目链接:http://poj.org/problem?id=2006 解题报告: 题意看了半天,没看懂,再加上化学没学好,更加让我头痛. 假设1L溶解了x摩尔的酸:ka=m*x*nx/ori-x; ...