CSAcademy Palindromic Concatenation 字符串哈希
题意:
题目链接
给出\(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 字符串哈希的更多相关文章
- HDU 1880 魔咒词典(字符串哈希)
题目链接 Problem Description 哈利波特在魔法学校的必修课之一就是学习魔咒.据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一 ...
- 洛谷P3370 【模板】字符串哈希
P3370 [模板]字符串哈希 143通过 483提交 题目提供者HansBug 标签 难度普及- 提交 讨论 题解 最新讨论 看不出来,这题哪里是哈希了- 题目描述 如题,给定N个字符串(第i个 ...
- HDU2594 Simpsons’ Hidden Talents 字符串哈希
最近在学习字符串的知识,在字符串上我跟大一的时候是没什么区别的,所以恶补了很多基础的算法,今天补了一下字符串哈希,看的是大一新生的课件学的,以前觉得字符串哈希无非就是跟普通的哈希没什么区别,倒也没觉得 ...
- LA 6047 Perfect Matching 字符串哈希
一开始我用的Trie+计数,但是不是计多了就是计少了,后来暴力暴过去的…… 看了别人的代码知道是字符串哈希,但是仍有几个地方不理解: 1.26^500溢出问题 2.没考虑哈希碰撞? 跪求指点! #in ...
- AC日记——【模板】字符串哈希 洛谷 3370
题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...
- 从Hash Killer I、II、III论字符串哈希
首先,Hash Killer I.II.III是BZOJ上面三道很经典的字符串哈希破解题.当时关于II,本人还琢磨了好久,但一直不明白为啥别人AC的代码都才0.3kb左右,直到CYG神犇说可以直接随机 ...
- 【NOIP模拟】Grid(字符串哈希)
题目背景 SOURCE:NOIP2016-RZZ-1 T3 题目描述 有一个 2×N 的矩阵,矩阵的每个位置上都是一个英文小写字符. 现在需要从某一个位置开始,每次可以移动到一个没有到过的相邻位置,即 ...
- 洛谷 P3370 【模板】字符串哈希
洛谷 P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的 ...
- cf_514C(字符串哈希)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121897#problem/G Watto and Mechanism Time ...
随机推荐
- Java—继承
继承 继承是类与类的一种关系,是一种“is a”的关系.注意:java中的继承是单继承,一个类只有一个父类. 继承的好处:子类拥有父类的所有属性和方法(private修饰的无效),实现代码的复用 语法 ...
- Canvas 中drawImage 绘制不出图片
在使用Canvas的drawImage绘制图片时,却发现绘制不出图片,原因是图片是异步加载,图片加载完再绘制. //html <img src="1.png" /> & ...
- cnblog编辑Latex数学公式
Latex在线公式编辑器 http://www.codecogs.com/latex/eqneditor.php 1. 行内公式: code $ \sqrt{a^2} $ display $ \sqr ...
- 显示、更改ubuntu linux主机名(计算机名)
在bash中输入hostname可以显示计算机名.Linux和windows都可以使用这条指令. 主机名保存在/etc/hostname文件中 需要进入Root权限才可以修改该文件. sudo ged ...
- Nagios监控ActiveMQ插件开发和部署注意事项
前提,监控服务器是Ubuntu14 操作系统.被监控服务器是RHEL6.5 RHEL7 1.自定义插件可以使用bash.python等脚本来实现. 2.通过nrpe插件来实现监控服务器和被监控主机之间 ...
- 【转载】#324 - A Generic Class Can Have More than One Type Parameter
A generic class includes one or more type parameters that will be substituted with actual types when ...
- CoreData的学习
第一步:创建项目是勾选coredata,当然创建的时候没有勾选,之后还可以手动生产, 然后:创建数据库模型,及为其添加模型的属性. 然后生成模型文件: 注意⚠️:首先设置为Manual/None 不 ...
- 2018.8.5 Bootstrap 使用
Bootstrap的环境搭建 <link rel="stylesheet" type="text/css" href="css/bootstra ...
- Vuex进阶
1.插件 下面以一个对state进行持久化存储的插件为例进行介绍: 代码结构: saveInLocal.js export default function (store) { if (localSt ...
- IE问题——列表项图像
等我们实现列表时,经常会遇到一种情况:需要为列表的每一项的前面添加一个列表项图像. 我们在查阅W3C时会发现,在CSS中已经为我们提供了实现方法——“list-style-type”,我们来看看它的实 ...