题意:

题目链接

给出\(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. uLua学习之HelloWorld(一)

    前言 好久都没有写过文章了,现在正好在看有关unity3d的热更新方案,在网上找了很久,发现了ulua这个插件,感觉还是不错的,反正自己是个初学者,多了解一些知识应该是没有什么问题的.说起ulua,就 ...

  2. python网络编程-socketserver模块

    使用socketserver 老规矩,先引入import socketserver 必须创建一个类,且继承socketserver.BaseRequestHandler 这个类中必须重写handle( ...

  3. Struts2_HelloWorld1

    打开 eclipse,新建 web 项目. 因为可能需要 jstl 表达式,所以添加 jstl需要的jar包. 下载链接:http://pan.baidu.com/s/1hr6mBI0 将jar拷贝至 ...

  4. 心得整理之一--RDLC多数据源多表

    我将项目中的一部分提炼出来,写了这个Demo. 先说一下需求, 从 API接口, 获取数据源, 调用RDLC 生成PDF文件. (后面还有涉及到使用福昕PDf阅读器进行设置文件自定义内容,以供外部程序 ...

  5. PHP设计模式之单例模式

    <?php #千锋PHP http://www.qfedu.com/php/? #千锋PHP http://www.qfedu.com/php/? namespace app; /** * Cl ...

  6. python 字符串部分总结

    字符串 对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符 >>> ord('A') 65 >>> ord ...

  7. Eclipse快捷键功能

    转载一篇另人写的:https://blog.csdn.net/qq_30617755/article/details/50781003 Eclipse的编辑功能非常强大,掌握了Eclipse快捷键功能 ...

  8. 2018.8.2 Juint测试介绍及其命名的规范

    JUnit - 测试框架 什么是 Junit 测试框架? JUnit 是一个回归测试框架,被开发者用于实施对应用程序的单元测试,加快程序编制速度,同时提高编码的质量.JUnit 测试框架能够轻松完成以 ...

  9. Spring Quartz *.QRTZ_LOCKS' doesn't exist

    ERROR [org.springframework.web.context.ContextLoader] - Context initialization failedorg.springframe ...

  10. sql查询字段值长度判断是否18位

    SELECT * FROM 表名 WHERE LENGTH(字段)= OR 字段为null IS NULL OR 字段为空='' SELECT * FROM 表名 WHERE LENGTH(字段)&g ...