• 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;
    }
    
    
  • 相关阅读:
    飞机游戏
    nodejs制作爬虫程序
    关于解析字符串
    引用nodejs的url模块实现url路由功能
    appium定位学习
    appium移动端自动化测试的一些感想
    appium的工作原理
    appium desktop 定位弹出框时报错
    APPium连接真机输入框中输入的内容与代码中不一致
    appium 链接真机后,运行代码,但是APP并没有启动
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/13996283.html
Copyright © 2020-2023  润新知