题解:P15696 [2018 KAIST RUN Spring] QueryreuQ
nancyaning · · 题解
一、题意理解&分析题面
我们通读题面以后可以发现题目要求我们操作一个字符串,每次在末尾加或减一个字符,考虑到题目要求我们求回文串,我们可以联想到一些关于求回文串算法,这时我们就可以想到马拉车算法,其可以帮助我们在
(为什么是
在此基础上我们观察到数据范围,
简单做法总结:先预处理字符串达到题目输入效果,再使用马拉车模板直接计算回文串个数,最后输出即可。
(不要忘记 manacher 内有些全局变量需要多测清空,而字符串不需要清空因为是在原先基础上操作的!)
难点就在于实现马拉车了然后就差不多了。
二、代码实现
#include <bits/stdc++.h>
#define ll long long
using namespace std;
string s1;
int c=0,ri=0;
string init(string s1)//马拉车中的预处理字符串
{
string s;
for(int i=0;i<s1.size();i++)
{
s+='#';
s+=s1[i];
}
s+='#';
return s;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)//习惯使用T,其实就是题目里的Q次操作
{
c=0,ri=0;
char a;
cin>>a;
if(a=='-')//这个地方就是按照题目要求添加字符或删减字符
{
string nows;
for(int i=0;i<s1.size()-1;i++)nows+=s1[i];
s1=nows;
}
else s1=s1+a;
string s=init(s1);//从这里开始就是马拉车模板,详细参见P3805
int n=s.size()-1;
vector<int> r(n+1,0);
int ans=0;
for(int i=1;i<=n;i++)
{
if(i<ri)
{
int j=2*c-i;
r[i]=min(r[j],ri-i);
}
else r[i]=0;
while(i-r[i]>=0&&i+r[i]<=n&&s[i-r[i]]==s[i+r[i]])r[i]++;
if(i+r[i]>ri)c=i,ri=i+r[i];
ans+=r[i]/2;//累加每一个回文中心的回文串数量(因为r[i]表示的是最长回文半径,而其包含了上面马拉车预处理的"#",所以事实上其应当是原字符串的长度。为求出长度小于r[i]且与其同个回文中心的数量,我们应当除以2)
}
cout<<ans<<" ";//直接输出即可
}
return 0;
}
以上就是全部内容,希望可以帮助到你。