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 ...
随机推荐
- PhoneGap&jQuery Mobile应用开发环境配置(For Android)
关于移动应用为什么用PhoneGap和jQuery Mobile本文不再赘述,有兴趣的童鞋可以自行问“度娘”,有很多这方面的文章.本文主要介绍PhoneGap&jQuery Mobile移动应 ...
- Ubuntu 16.10 安装mysql
打开终端 sudo apt update 完成后 sudo apt install mysql-server 中间会提示设置root 账户的密码 有的文章提到 还要 install mysql-cli ...
- System Center Configuration Manager 2016 配置安装篇(Part2)
步骤4.安装SCCM当前分支(版本1802) 注意:以管理员身份在ConfigMgr服务器(CM01)上执行以下操作. 为此,在Configuration Manager服务器(CM16)上,打开W ...
- LeetCode OJ Palindrome Number(回文数)
class Solution { public: bool isPalindrome(int x) { ,init=x; ) return true; ) return false; ){ r=r*+ ...
- 使用ABAP Push Channel(APC)开发的乒乓球游戏,可双打
url: https://:/sap/bc/apc_test/ping_pong/game 或者事务码SICF, 输入ping_pong, 按F8: 选中搜索结果,点右键选择Test,即可打开url. ...
- C4C和CRM里获取当前登录用户分配的Organization Unit信息
C4C 如何查看某个用户分配的组织单元ID: 在Employee的Organization Data区域内看到分配的组织名称,如下图红色下划线所示: 现在的需求就是使用ABSL获取当前登录用户分配的O ...
- mac 下使用 ikbcG87 及使用 karabiner 改大小写键
前言 一直使用 mac ,对于机械键盘还处于刚入坑阶段,作为小白还是选择能够兼容 mac 的机械键盘,于是选择了 ikbcG87 "双子座" 1.使用 ikbc G87 mac 模 ...
- mm_struct简要解析
http://blog.chinaunix.net/uid-20729583-id-1884615.html struct mm_struct { /* 指向线性区对象的链表头 ...
- 【BZOJ4555】[TJOI2016&HEOI2016] 求和(NTT)
点此看题面 大致题意: 计算\(\sum_{i=0}^n\sum_{j=0}^iS(i,j)*2^j*(j!)\),其中\(S\)为第二类斯特林数. 推式子 首先让我们来推一波式子: 因为当\(i&l ...
- 在写移动端时,a标签或者input标签等 在手机上点击背后会有阴影的解决办法
a,input{-webkit-tap-highlight-color:rgba(255,0,0,0);} 被背景设置成透明的就行了