题意:

题目链接

给出\(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. 2017年10月31日结束Outlook 2007与Office 365的连接

    2017 年10月31日 ,微软即将推出 Office 365中Exchange Online邮箱将需要Outlook for Windows的连接,即通过HTTP Over MAPI方式,传统使用R ...

  2. C#学习基础,面向对象的三大特征

    学习C#编程,相信大家除了经常接触的是hello world之外,更多的是进一步的去熟悉这门语言的基本特征,以及有哪些概念是我们必要掌握了解的,相信大家都是会知道面向对象的三大特性分别是:封装,继承, ...

  3. 显示C++ vector中的数据

    C++ 中的vector是一个容器数据类型,不能使用cout直接显示容器中的值. 以下程序中,myvector 是一个vector数据类型.将myvector替换为需要输出的vector. for(i ...

  4. CVE-2017-8464 LNK文件(快捷方式)远程代码执行漏洞复现

    北京时间2017年6月13日凌晨,微软官方发布6月安全补丁程序,“震网三代” LNK文件远程代码执行漏洞(CVE-2017-8464)和Windows搜索远程命令执行漏洞(CVE-2017-8543) ...

  5. 使用ABAP代码创建S/4HANA里的Sales Order

    下图是使用ABAP代码创建的S/4HANA的Sales Order的截图: 其中红色区域的值是我代码里硬编码的,而蓝色是函数SD_SALESDOCUMENT_CREATE自己创建的. 来看下代码: D ...

  6. UVA 11983 Weird Advertisement

    题意:求矩形覆盖k次以上的区域总面积. 因为k≤10,可以在线段树上维护覆盖次数为0,...,k, ≥k的长度数量. 然后就是一个离散化以后扫描线的问题了. 离散化用的是半开半闭区间,以方便表示没有被 ...

  7. 过河问题(POJ1700)

    题目链接:http://poj.org/problem?id=1700 解题报告: 1.贪心算法,每次过两个速度最慢的人,抵消那个较慢的人的时间. #include <stdio.h> # ...

  8. P1909 买铅笔

    题目描述 P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物.她发现商店一共有 33种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同.为了公平起 见,P老师决定只买同一种包装的铅笔 ...

  9. Spring boot 集成Spring Security

    依赖jar <dependency> <groupId>org.springframework.cloud</groupId> <artifactId> ...

  10. numpy中的inf

    numpy中的inf表示一个无限大的正数 import numpy x = numpy.inf x>9999999999999999999 结果为: True