Non Super Boring Substring 题解(hash+思维)

题目链接

题目大意

给你一个长度为d(d<=1e5)的字符串,要你求有多少个子串满足这个子串不包含长度大于等于k的回文子串

题目思路

首先可以hash预处理,然后O(1)用前缀hash值和后缀hash值求一个字符串是否是回文串

其实你只要枚举每个点当作左端点,求右端点最远能到那里即可

回文串可能最多达到(n^2)个,但你可以思考一下其实你只要考虑长度为k和k+1的字符串即可

具体证明有点麻烦自己可以画图去考虑一下,因为长度更长的回文串必有子串长度为k或k+1

但是长度更短的回文串,影响明显是比长度更大的回文串大,即可以使得左端点固定,右端点更左

然后把所有长度为k或者k+1的回文串,先按右端点,然后按左端点排序

用双指针的思想求出每个点当作左端点,可以到达的最远右端点

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here
");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=2017;
const double eps=1e-10;
int k;
char s[maxn];
int d;
ull base[maxn],pre[maxn],suf[maxn];
pair<int,int> pa[maxn];
void init(){
    base[0]=1;
    for(int i=1;i<=d;i++){
        base[i]=base[i-1]*29;
    }
    for(int i=1;i<=d;i++){
        pre[i]=pre[i-1]*29+s[i]-'a'+1;
    }
    for(int i=d;i>=1;i--){
        suf[i]=suf[i+1]*29+s[i]-'a'+1;
    }
}
ll getprehash(int l,int r){
    return pre[r]-pre[l-1]*base[r-l+1];
}
ll getsufhash(int l,int r){
    return suf[l]-suf[r+1]*base[r-l+1];
}
int main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%d %s",&k,s+1);
        d=strlen(s+1);
        init();
        int cnt=0;
        for(int i=1;i+k-1<=d;i++){
            if(getprehash(i,i+k-1)==getsufhash(i,i+k-1)){
                pa[++cnt]={i+k-1,i};
            }
        }
        for(int i=1;i+k+1-1<=d;i++){
            if(getprehash(i,i+k)==getsufhash(i,i+k)){
                pa[++cnt]={i+k,i};
            }
        }
        sort(pa+1,pa+1+cnt);
        int now=1;
        ll ans=0;
        for(int i=1;i<=d;i++){
            while(pa[now].se<i&&now<=cnt){
                now++;
            }
            if(now==cnt+1){
                ans+=d-i+1;
            }else{
                ans+=pa[now].fi-1-i+1;
            }
        }
        printf("%lld
",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hunxuewangzi/p/13996283.html