【马拉车】Gym 101864J,马拉gym101864j
分享于 点击 34156 次 点评:213
【马拉车】Gym 101864J,马拉gym101864j
题目链接<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;
}
相关文章
- 暂无相关文章
用户点评