1. 程式人生 > >【馬拉車】Gym 101864J - Non Super Boring Substring

【馬拉車】Gym 101864J - Non Super Boring Substring

題目連結<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;
}