码迷,mamicode.com
首页 > 其他好文 > 详细

FJUT3703 这还是一道数论题(二分 + hash + manacher)题解

时间:2019-04-07 00:21:17      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:des   png   www   题目   for   写法   sort   image   总数   

Problem Description

最后来个字符串签个到吧,这题其实并不难,所需的算法比较基础,甚至你们最近还上过课。

为了降低难度,免得所有人爆零。这里给几个提示的关键字 :字符串,回文,二分,哈希. 注意要对奇偶回文分开二分

这样还不会做,说明基础有所欠缺。

给你一个字符串A和一个字符串B,请你求一个满足以下要求的所有字符串中,最长的字符串C的长度:

  1. C必须同时是A和B的子串,即A和B中都必须存在一个子区间和C长得一样

  2. C必须是一个回文,即正过来读和反过来读都一样

 

Input

多组数据,请处理到EOF

每组数据包含,两行,每行都是仅由小写字符构成的字符串,代表A和B。

对于30%的数据。

保证|A|,|B|<=1000,且单个文件的字符总数小于10000

对于100%的数据

保证|A|,|B|<=100000,且单个文件的字符总数小于2e6

其中70%的数据答案为奇数哦

因为没有处理掉字符串尾巴上多余的‘\r‘,所以为了防止读到‘\r‘ 推荐使用scanf("%s");

链接

 

思路:

技术图片

 

按照旺神的思路来。

我是把串先按照Manacher处理成只有奇数回文,然后找到最大回文串R,显然最终答案只可能是R,R-2,R-4....那么我直接二分这个最终长度。然后用hash找是否存在这个长度的公共子串,但是我只会Hash的O(nlogn + m)写法啊。在T了几发之后发现题目时限又开大了,8000ms用7400ms擦过,旺神nb。

代码:

#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 = 200000 + 10;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
char s[maxn], p[maxn], snew1[maxn], snew2[maxn];
int pos[maxn], num[maxn];
ull hs[maxn], hp[maxn], fac[maxn], q[maxn];
ull getHashP(int l, int r){
    return hp[r] - (l == 0? 0 : hp[l - 1]) * fac[r - l + 1];
}
ull getHashS(int l, int r){
    return hs[r] - (l == 0? 0 : hs[l - 1]) * fac[r - l + 1];
}
int lens, lenp, lenSnew;
int init(int len){
    int cnt = 0;
    snew1[cnt] = $;
    for(int i = 0; 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 = 0, ans = -1;
    for(int i = 2; i < cnt; i++){
        if(pos[id] + id > i){
            pos[i] = min(pos[2 * id - i], pos[id] + id - i);
        }
        else pos[i] = 1;
        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] - 1);
    }
    return ans; //长度
}
bool mid(int l, int r, ull aim){
    while(l <= r){
        int m = (l + r) >> 1;
        if(q[m] >= aim){
            if(q[m] == aim) return true;
            r = m - 1;
        }
        else l = m + 1;

    }
    return false;
}
bool check(int len){
    int tol = 0;
    for(int i = 0; i + len - 1 < lenp; i++){    //p子串
        q[tol++] = getHashP(i, i + len - 1);
    }
    sort(q, q + tol);
    for(int i = 2; i < lenSnew; i += 2){  //找s
        if(pos[i] - 1 >= len){
            int R = len / 2;
            int position = i / 2 - 1;   //实际位置
            ull aim = getHashS(position - R, position + R);
            if(mid(0, tol - 1, aim)){
                return true;
            }

        }
    }
    return false;
}
int main(){
    fac[0] = 1;
    for(int i = 1; i < maxn; i++)
        fac[i] = fac[i - 1] * seed;
    while(scanf("%s%s", snew1, snew2) != EOF){
        lens = 0, lenp = 0;
        //改成全奇
        s[lens++] = 0;
        int len1 = strlen(snew1);
        for(int i = 0; i < len1; i++){
            s[lens++] = snew1[i];
            s[lens++] = 0;
        }
        p[lenp++] = 0;
        int len2 = strlen(snew2);
        for(int i = 0; i < len2; i++){
            p[lenp++] = snew2[i];
            p[lenp++] = 0;
        }


        /*if(lens > 80000 && lenp > 80000){
            printf("woxianbuzuo\n");
            continue;
        }*/

        hs[0] = hp[0] = 0;
        for(int i = 0; i < lens; i++){  //hash
            if(i == 0) hs[i] = s[i];
            else hs[i] = hs[i - 1] * seed + s[i];
        }
        for(int i = 0; i < lenp; i++){
            if(i == 0) hp[i] = p[i];
            else hp[i] = hp[i - 1] * seed + p[i];
        }

        int cnt = lenSnew;
        int L = 1, R = Manacher(); //对s马拉车
        int l = 1, r = R / 2; //R = 2 * r + 1
        int ans = 0;
        while(l <= r){
            int m = (l + r) >> 1;
            if(check(2 * m + 1)){
                ans = 2 * m + 1;
                l = m + 1;
            }
            else{
                r = m - 1;
            }
        }
        printf("%d\n", ans / 2);
    }
    return 0;
}

 

FJUT3703 这还是一道数论题(二分 + hash + manacher)题解

标签:des   png   www   题目   for   写法   sort   image   总数   

原文地址:https://www.cnblogs.com/KirinSB/p/10663751.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!