【马拉车】Gym 101864J - Non Super Boring Substring

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/82953196

题目链接<http://codeforces.com/gym/101864/attachments>


题意:

给出一个字符串,求出不包含回文长度大于等于k的子串的个数。


题解:

我是先计算不符合条件的数目,然后用总的减去。

先直接一遍马拉车,求出所有的回文半径。

对于每一个回文长度大于等于k的中心,它会有一个范围(l,r)。从左往右考虑每一个范围,它的右端点取值范围是>=r,左端点的范围是<=l且大于前一个的左端点。

而对于这个范围要分奇偶情况讨论,因为如果回文中心是#,那么大于等于k且长度最小的一定是偶数。而如果回文中心是字母,那就是奇数。所以每一个范围的长度是k或者k+1。

然后就是计算长度可能比较麻烦吧。


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<map>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll N=1e6+7;
char s[N],ma[N*2];
ll p[N*2];
void mana(char *s,ll len){
    ll l=0;
    ma[l++]='$';
    ma[l++]='#';
    for(ll i=0;i<len;i++){
        ma[l++]=s[i];
        ma[l++]='#';
    }
    ma[l]=0;
    ll pos=0,R=0;
    for(ll i=0;i<l;i++){
        if(i<R) p[i]=min(p[pos*2-i],R-i);
        else p[i]=1;
        while(ma[i+p[i]]==ma[i-p[i]]) p[i]++;
        if(i+p[i]>R) pos=i,R=i+p[i];
    }
}
int main(){
    ll t,k;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&k);
        scanf("%s",s);
        ll len=strlen(s);
        ll ans=(1+len)*len/2;
        mana(s,len);
        ll tmp=0,lst=0;
        ll sz=strlen(ma)-2;
        if(k&1){
            for(ll i=0;i<2*len+2;i++){
                if(p[i]-1>=k){
                    if(ma[i]=='#'){
                        tmp+=(i/2-(k+1)/2+1-lst)*(sz/2-i/2-(k+1)/2+1);
                        lst=i/2-(k+1)/2+1;
                    }
                    else{
                        tmp+=(i/2-k/2-lst)*(sz/2-i/2-k/2+1);
                        lst=i/2-k/2;
                    }
                }
            }
        }
        else{
            for(ll i=1,j=0;i<2*len+2;i++,j++){
                if(p[i]-1>=k){
                    if(ma[i]=='#'){
                        tmp+=(i/2-k/2+1-lst)*(sz/2-i/2-k/2+1);
                        lst=i/2-k/2+1;
                    }
                    else{
                        tmp+=(i/2-(k+1)/2-lst)*(sz/2-i/2-(k+1)/2+1);
                        lst=i/2-(k+1)/2;
                    }
                }
            }
        }
        printf("%lld\n",ans-tmp);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/82953196