当前位置:网站首页>(2022牛客多校五)G-KFC Crazy Thursday(二分+哈希)
(2022牛客多校五)G-KFC Crazy Thursday(二分+哈希)
2022-08-03 03:24:00 【AC__dream】
题目:
样例输入:
6
kfccfk样例输出:
3 3 3题意:给你一个n,以及一个长度为n的字符串,字符串由小写字母组成,然后问里面有多少个分别以k、f、c字母结尾的回文字符串。
这道题好像标解是回文自动机,但是我不太会,下面我说一下这道题二分+哈希的思路。
看这道题之前大家应该先会求解一个字符串中的最大回文子串,不会的小伙伴可以看这里:求最大回文子串长度_AC__dream的博客-CSDN博客
首先可以确定的一点是所有的回文串都会有中心字符,如果回文子串长度为奇数,那么就只有一个中心字符,否则就有两个中心字符,所以我们可以枚举以每个字符作为中心时的最长回文串,然后再从中找到以k、f、c结尾的回文串,方法就很简单了,就是说假如我们现在以字符x为中心的最长回文串长度是11,这个长度为11的回文串里面有8个f,那么显然就会有4个以f作为结尾的回文串,毕竟回文串是对称的,所以我们就是这个思路,枚举一下以每个字母作为中心的回文串,事先处理一下k、f、c的数目前缀和,这样可以O(1)判断区间[l,r]里面某个特殊字母出现的次数。注意还有偶数的情况,这个时候就需要枚举一下两个中心点中的一个,左边还是右边都可以,需要注意的就是不存在的情况,就是说两个中心点字母不相同的时候是不存在的情况,二分+哈希求解回文子串长度的方法我已经在之前博客中介绍过了,上面附有博客地址,具体细节见代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=5e5+10;
typedef unsigned long long ull;
ull p[N],sum1[N],sum2[N];
int sk[N],sf[N],sc[N];//sx[i]标记前i个位置有多少个字符x
char s[N];
ull get(int l,int r,int op)
{
if(op==1)
return sum1[r]-sum1[l-1]*p[r-l+1];
else
return sum2[l]-sum2[r+1]*p[r-l+1];
}
int main()
{
int n;
p[0]=1;
for(int i=1;i<N;i++)
p[i]=p[i-1]*131;
while(scanf("%d",&n)!=EOF)
{
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
sum1[i]=sum1[i-1]*131+s[i];
if(s[i]=='k') sk[i]=sk[i-1]+1;
else sk[i]=sk[i-1];
if(s[i]=='f') sf[i]=sf[i-1]+1;
else sf[i]=sf[i-1];
if(s[i]=='c') sc[i]=sc[i-1]+1;
else sc[i]=sc[i-1];
}
sum2[n+1]=0;
for(int i=n;i>=1;i--)
sum2[i]=sum2[i+1]*131+s[i];
long long ansk,ansf,ansc;
ansk=ansf=ansc=0;
for(int i=1;i<=n;i++)//枚举长度为奇数情况下第i个位置为中心点的回文子串数目
{
int l=0,r=min(n-i,i-1);
while(l<r)
{
int mid=l+r+1>>1;
if(get(i-mid,i+mid,1)==get(i-mid,i+mid,2)) l=mid;
else r=mid-1;
}
ansk+=sk[i+l]-sk[i-1];
ansf+=sf[i+l]-sf[i-1];
ansc+=sc[i+l]-sc[i-1];
}
for(int i=1;i<=n;i++)//枚举长度为偶数情况下第i个位置为两个中心点左边的那个中心点的回文子串数目
{
int l=0,r=min(n-i,i);
while(l<r)
{
int mid=l+r+1>>1;
if(get(i-mid+1,i+mid,1)==get(i-mid+1,i+mid,2)) l=mid;
else r=mid-1;
}
if(l==0) continue;
ansk+=(sk[i+l]-sk[i-l])/2;
ansf+=(sf[i+l]-sf[i-l])/2;
ansc+=(sc[i+l]-sc[i-l])/2;
}
printf("%lld %lld %lld\n",ansk,ansf,ansc);
}
return 0;
}
边栏推荐
- 高等代数_证明_矩阵乘以自身的转置的特征值不小于0
- 【动态规划--01背包】HJ16 购物单
- AttributeError: module ‘xxx‘ has no attribute
- 【剑指offer】——股票的最大利润
- 中原银行实时风控体系建设实践
- Kotlin multiplication, how do I multiply smaller and smaller?
- Scala基础【异常、隐式转换、泛型】
- 爆肝22个ES6知识点
- leetcode:140. 单词拆分 II
- Jincang Database Pro*C Migration Guide (3. KingbaseES Pr*oc Compatibility with Oracle Pro*c)
猜你喜欢
随机推荐
JS高级 之 Proxy-Reflect 使用详解
【TA-霜狼_may-《百人计划》】美术2.5 模型常见问题及规范
QT之鼠标和键盘事件重写
【基础数学--埃氏筛】204. 计数质数
Postman如何做接口自动化测试?
shell之条件语句(条件测试、if语句,case语句)
高等代数_笔记_配方法标准化二次型
企业上云规划与云原生环境设计
软件测试个人求职简历该怎么写,模板在这里
C语言实验十一 指针(一)
这个困扰程序员50年的问题,终于要被解决了?
Kotlin multiplication, how do I multiply smaller and smaller?
有大佬知道 使用flinksql是 同步的日期字段为null的话怎么处理吗
【GO记录】从零开始GO语言——用GO语言做一个示波器(二)基于arduino的简易示波器
问下有用sql server flink-sql-connector-sqlserver-cdc-2
对话框管理器第四章:对话框消息循环
05-分布式计算框架
ROS2自学笔记:机器视觉基础
ESP8266-Arduino编程实例-MAX6675冷端补偿K热电偶数字转换器驱动
leetcode:151. 颠倒字符串中的单词









