当前位置:网站首页>(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;
}
边栏推荐
- Auto.js Pro 计算脚本运行时间
- AttributeError: module ‘xxx‘ has no attribute
- # RACE32——高级断点的设置和应用
- ESP8266-Arduino编程实例-MAX6675冷端补偿K热电偶数字转换器驱动
- 移植RT-Thread编译报错thumb conditional instruction should be in IT block
- uniapp中动态修改导航栏标题
- Pro * C Jin Cang database migration guide (4) KingbaseES Pro * C migration guide)
- 中非合作论坛非洲产品电商推广季启动 外交部:推动中非合作转型升级
- 基于 jetpack compose,使用MVI架构+自定义布局实现的康威生命游戏
- 【动态规划--01背包】HJ16 购物单
猜你喜欢
随机推荐
stdio.h(本机代码)
Jincang Database OCCI Migration Guide (5. Program Development Example)
QT之鼠标和键盘事件重写
Jmeter TCP/UDP测试
智能健身动作识别:PP-TinyPose打造AI虚拟健身教练!
ClickHouse卸载、重安装
【leetcode热题Hot100】——任务调度器
我的“眼睛”就是尺!
leetcode:162. 寻找峰值
ESP8266-Arduino编程实例-MCP3008-ADC转换器驱动
Chapter 8 Character Input Output and Input Validation
浅谈用KUSTO查询语言(KQL)在Azure Synapse Analytics(Azure SQL DW)审计某DB账号的操作记录
【GraphQL】使用Hot Chocolate和.NET 6构建GraphQL应用
基于 jetpack compose,使用MVI架构+自定义布局实现的康威生命游戏
SqlSession [[email protected]]
Auto. Js scripts run time calculated Pro
Domino服务器SSL证书安装指南
leetcode:151. 颠倒字符串中的单词
mysql-installer安装教程(详细图文)
sql问题,如何能做到先声明表的名称,例如product202201,表示2022年一月份的货物表,再在声明过的表中查找,下面的代码运行时有错误显示找不到表table_name,请问改如何进行修改