【馬拉車】Gym 101864J - Non Super Boring Substring
阿新 • • 發佈:2018-11-10
題目連結<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; }