FJUT3703 这还是一道数论题(二分 + hash + manacher 或者 STL + hash 或者 后缀数组 + hash)题解
最后来个字符串签个到吧,这题其实并不难,所需的算法比较基础,甚至你们最近还上过课。
为了降低难度,免得所有人爆零。这里给几个提示的关键字 :字符串,回文,二分,哈希. 注意要对奇偶回文分开二分
这样还不会做,说明基础有所欠缺。
给你一个字符串A和一个字符串B,请你求一个满足以下要求的所有字符串中,最长的字符串C的长度:
C必须同时是A和B的子串,即A和B中都必须存在一个子区间和C长得一样
C必须是一个回文,即正过来读和反过来读都一样
多组数据,请处理到EOF
每组数据包含,两行,每行都是仅由小写字符构成的字符串,代表A和B。
对于30%的数据。
保证|A|,|B|<=1000,且单个文件的字符总数小于10000
对于100%的数据
保证|A|,|B|<=100000,且单个文件的字符总数小于2e6
其中70%的数据答案为奇数哦
因为没有处理掉字符串尾巴上多余的'\r',所以为了防止读到'\r' 推荐使用scanf("%s");
思路:
更新2.0:
旺神nb。发现A了之后就能看所有人代码了
终于找到Hash的O(n)找公共子串的方法了,直接用unordered_map储存所有满足长度的回文子串。unordered_map查询接近常数级,就是O(1),插入反正比map快,所以总体就是O(n)级。
然后就从7000ms瞬间降到1400ms
代码2.0我没有预处理成全奇回文,而是直接分类奇偶二分。显然我们可以优化一下,奇偶遍历存在与否时可以直接两步两步走,因为奇偶的回文中心刚好交错。然后我们假如先二分奇数,得到一个长度R,那么我二分偶数回文半径至少R / 2 + 1,否则没有意义。我们直接用unordered_map储存s串的回文答案,然后O(n)判断p中有没有,如果怕Hash冲突,可以再验算一边是否一样。
然后我发现时限变成4000ms了...7s的代码卡掉了...只能用2.0的代码过...
这道题后缀数组也能做,JQtxdy +
----------------代码1.0分割线(已T)----------------------------
按照旺神的思路来。
我是把串先按照Manacher处理成只有奇数回文,然后找到最大回文串R,显然最终答案只可能是R,R-2,R-4....那么我直接二分这个最终长度。然后用hash找是否存在这个长度的公共子串,但是我只会Hash的O(nlogn + m)写法啊。在T了几发之后发现题目时限又开大了,8000ms用7400ms擦过,旺神nb。
代码2.0:
#include<cmath>
#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = + ;
const ull seed = ;
const int INF = 0x3f3f3f3f;
const int MOD = ;
char s[maxn], p[maxn], snew1[maxn];
int pos[maxn], num[maxn];
ull hs[maxn], hp[maxn], fac[maxn], q[maxn];
inline ull getHashP(int l, int r){
return hp[r] - (l == ? : hp[l - ]) * fac[r - l + ];
}
inline ull getHashS(int l, int r){
return hs[r] - (l == ? : hs[l - ]) * fac[r - l + ];
}
int lens, lenp, lenSnew;
int init(int len){
int cnt = ;
snew1[cnt] = '$';
for(int i = ; i < len; i++){
snew1[++cnt] = '#';
snew1[++cnt] = s[i];
}
snew1[++cnt] = '#';
snew1[++cnt] = '\0';
return cnt;
}
int Manacher(){
int cnt = init(lens);
lenSnew = cnt;
int id = , ans = -;
for(int i = ; i < cnt; i++){
if(pos[id] + id > i){
pos[i] = min(pos[ * id - i], pos[id] + id - i);
}
else pos[i] = ;
while(snew1[i - pos[i]] == snew1[i + pos[i]])
pos[i]++;
if(id + pos[id] < i + pos[i])
id = i;
ans = max(ans,pos[i] - );
}
return ans; //长度
}
bool mid(int l, int r, ull aim){
while(l <= r){
int m = (l + r) >> ;
if(q[m] >= aim){
if(q[m] == aim) return true;
r = m - ;
}
else l = m + ; }
return false;
}
unordered_map<ull, int> mp;
//$#a#a#a#0
bool checkJi(int len){
mp.clear();
for(int i = ; i + len - < lenSnew; i += ){ //s
if(pos[i] - >= len){
int R = len / ;
int position = i / - ; //实际位置
mp[getHashS(position - R, position + R)] = ;
}
}
for(int i = ; i + len - < lenp; i++){
ull aim = getHashP(i, i + len - );
if(mp.count(aim)) return true;
}
return false;
}
//$#c#a#a#a#a#0
bool checkOu(int len){
mp.clear();
for(int i = ; i + len - < lenSnew; i += ){ //s
if(pos[i] - >= len){
int R = len / ;
int position = i / - ; //实际位置
mp[getHashS(position - R + , position + R)] = ;
}
}
for(int i = ; i + len - < lenp; i++){
ull aim = getHashP(i, i + len - );
if(mp.count(aim)) return true;
}
return false;
}
int main(){
fac[] = ;
for(int i = ; i < ; i++)
fac[i] = fac[i - ] * seed;
while(scanf("%s%s", s, p) != EOF){
lens = lenp = ;
hs[] = hp[] = ;
for(int i = ; s[i] != '\0'; i++){ //hash
if(i == ) hs[i] = s[i];
else hs[i] = hs[i - ] * seed + s[i];
lens++;
}
for(int i = ; p[i] != '\0'; i++){
if(i == ) hp[i] = p[i];
else hp[i] = hp[i - ] * seed + p[i];
lenp++;
} int R = Manacher(); //马拉车返回s最大长度
int l, r, ans = ;
l = , r = R / ;
while(l <= r){ //偶
int m = (l + r) >> ;
if(checkOu(m * )){
l = m + ;
ans = m * ;
}
else r = m - ;
}
l = ans / , r = R / ;
while(l <= r){ //奇
int m = (l + r) >> ;
if(checkJi(m * + )){
l = m + ;
ans = max(m * + , ans);
}
else r = m - ;
}
printf("%d\n", ans);
}
return ;
}
代码:
#include<cmath>
#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = + ;
const ull seed = ;
const int INF = 0x3f3f3f3f;
const int MOD = ;
char s[maxn], p[maxn], snew1[maxn], snew2[maxn];
int pos[maxn], num[maxn];
ull hs[maxn], hp[maxn], fac[maxn], q[maxn];
inline ull getHashP(int l, int r){
return hp[r] - (l == ? : hp[l - ]) * fac[r - l + ];
}
inline ull getHashS(int l, int r){
return hs[r] - (l == ? : hs[l - ]) * fac[r - l + ];
}
int lens, lenp, lenSnew;
int init(int len){
int cnt = ;
snew1[cnt] = '$';
for(int i = ; i < len; i++){
snew1[++cnt] = '#';
snew1[++cnt] = s[i];
}
snew1[++cnt] = '#';
snew1[++cnt] = '\0';
return cnt;
}
int Manacher(){
int cnt = init(lens);
lenSnew = cnt;
int id = , ans = -;
for(int i = ; i < cnt; i++){
if(pos[id] + id > i){
pos[i] = min(pos[ * id - i], pos[id] + id - i);
}
else pos[i] = ;
while(snew1[i - pos[i]] == snew1[i + pos[i]])
pos[i]++;
if(id + pos[id] < i + pos[i])
id = i;
ans = max(ans,pos[i] - );
}
return ans; //长度
}
bool mid(int l, int r, ull aim){
while(l <= r){
int m = (l + r) >> ;
if(q[m] >= aim){
if(q[m] == aim) return true;
r = m - ;
}
else l = m + ; }
return false;
}
bool check(int len){
int tol = ;
for(int i = ; i + len - < lenp; i++){ //p子串
q[tol++] = getHashP(i, i + len - );
}
sort(q, q + tol);
for(int i = ; i < lenSnew; i += ){ //找s
if(pos[i] - >= len){
int R = len / ;
int position = i / - ; //实际位置
ull aim = getHashS(position - R, position + R);
if(mid(, tol - , aim)){
return true;
} }
}
return false;
}
int main(){
fac[] = ;
for(int i = ; i < maxn; i++)
fac[i] = fac[i - ] * seed;
while(scanf("%s%s", snew1, snew2) != EOF){
lens = , lenp = ; //改成全奇回文
s[lens++] = '';
for(int i = ; snew1[i] != '\0'; i++){
s[lens++] = snew1[i];
s[lens++] = '';
}
p[lenp++] = '';
for(int i = ; snew2[i] != '\0'; i++){
p[lenp++] = snew2[i];
p[lenp++] = '';
} hs[] = hp[] = ;
for(int i = ; i < lens; i++){ //hash
if(i == ) hs[i] = s[i];
else hs[i] = hs[i - ] * seed + s[i];
}
for(int i = ; i < lenp; i++){
if(i == ) hp[i] = p[i];
else hp[i] = hp[i - ] * seed + p[i];
} int cnt = lenSnew;
int L = , R = Manacher(); //马拉车返回最大长度
int l = , r = R / ; //R = 2 * r + 1
int ans = ;
while(l <= r){
int m = (l + r) >> ;
if(check( * m + )){
ans = * m + ;
l = m + ;
}
else{
r = m - ;
}
}
printf("%d\n", ans / );
}
return ;
}
FJUT3703 这还是一道数论题(二分 + hash + manacher 或者 STL + hash 或者 后缀数组 + hash)题解的更多相关文章
- FJUT-这还是一道数论题
这还是一道数论题 TimeLimit:4000MS MemoryLimit:128MB 64-bit integer IO format:%lld Special Judge Problem D ...
- Uva12206 Stammering Aliens 后缀数组&&Hash
Dr. Ellie Arroway has established contact with an extraterrestrial civilization. However, all effort ...
- 后缀数组 hash求LCP BZOJ 4310: 跳蚤
后缀数组的题博客里没放进去过..所以挖了一题写写 充实下博客 顺便留作板子.. 一个字符串S中 内容不同的子串 有 sigma{n-sa[i]+1-h[i]} (噢 这里的h[]就是大家熟知的he ...
- HDU-4622 Reincarnation 后缀数组 | Hash,维护和,扫描
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给一个字符串,询问某字串的不同字串的个数. 可以用后缀数组来解决,复杂度O(n).先求出倍 ...
- BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)
题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...
- FJUT3701 这也是一道数论题(线段树)题解
Problem Description 好久没出数据结构题,现在赶紧来做道数据结构题热热身 小q现在要去银行,他有个很厉害的bug能看到前面排队的人.假如当前有人正在办理业务,那么肯定要等待前一个人完 ...
- fjutacm 3700 这是一道数论题 : dijkstra O(mlogn) 二进制分类 O(k) 总复杂度 O(k * m * logn)
/** problem: http://www.fjutacm.com/Problem.jsp?pid=3700 按二进制将k个待查点分类分别跑dijkstra **/ #include<std ...
- cogs2223. [SDOI2016 Round1] 生成魔咒(后缀数组 hash 二分 set
题意:对一个空串每次在后面加一个字符,问每加完一次得到的字符串有几个不同的子串. 思路:每个子串都是某个后缀的前缀,对于每个后缀求出他能贡献出之前没有出现过的前缀的个数,答案累加就行. 要求每个后缀的 ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
[题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...
随机推荐
- transform的兼容性写法浏览器 和 transition
transform:rotate(7deg); -ms-transform:rotate(7deg); /* IE 9 */ -moz-transform:rotate(7deg); /* Firef ...
- SecureCRT操作指令
连接服务器,文件——连接SFTP会话,然后可以help查看命令 传输文件需要明确并处在客户端和服务器端两个正确路径下, 服务器端的操作: cd——去服务器指定的路径 pwd——查看服务器端当前目录 l ...
- 解决在Windows10没有修改hosts文件权限
当遇到有hosts文件不会编辑或者,修改了没办法保存”,以及需要权限等问题如图: 我学了一招,先在交给你: 1.win+R 2.进入hosts的文件所在目录: 3.我们开始如何操作才能不出现权限问题那 ...
- Codeforces 1136D - Nastya Is Buying Lunch - [贪心+链表+map]
题目链接:https://codeforces.com/problemset/problem/1136/D 题意: 给出 $1 \sim n$ 的某个排列 $p$,再给出若干 $(x,y)$ 表示当序 ...
- Linux 中的 Install命令
Linux 中的 Install命令 更新时间:2017年09月25日 16:51:45 投稿:mrr 我要评论 install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户. ...
- 数据格式XML、JSON详解
一. XML数据格式 1.1 XML的定义 扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类 ...
- Spring Jdbc 框架整合的第一天
Spring Jdbc的概述 它是Spring框架的持久层子框架.用于对数据库的操作 什么是数据库的操作? 答:对数据库的增删改查 在使用Spring Jdbc框架,要用到一个类---->J ...
- cds view 创建和调用
cds view 是一个core data service, 能够将数据库表虚拟化为一个虚拟表(double).因为各个使用sap的公司,使用的数据库数据是不同的,所以提供一个数据库的虚拟. 通过向 ...
- 你不知道的JavaScript-1.作用域是什么
作用域是一套规则,用于确定在何处以及如何查找变量.函数等(标识符).如果查找的目的是对变量进行赋值,那么就会使用 LHS 查询:如果目的是获取变量的值,就会使用 RHS 查询. 赋值操作符会导致 LH ...
- ubuntu 安装完后对于开发需要做的事情
是从 https://www.osboxes.org/ubuntu/ 下载的vdi文件,估计vmware对应的应该也有. 1. 安装 openssh-server apt-get install op ...