前缀和(P2697 宝石串)
前言
每次做出来什么本来做不出的题目,就忍不住记录一下。不过大多时候隔几天来看,就发现,啊,我当时只是做了一道这么弱智的题目呀,哈哈。前缀和确实不算太难。。
传送门
题目大意:
给你一个字符串只含G和R,求一个最长子串长度,使得两个字符的长度相等。(给的字符串长小于1e6)
如:GRGGRG
答案是:4。
思路
题目中字符串很长,暴力枚举显然不可能。
但我们仔细一看,发现不过只有两个字符G和H。我们令G为1,令R为-1,那么GR的值就为0,这显然是一个可行的子串。
那再看GRGGRG,我们开一个a数组记录前i个字符的值,那么
a[0]=0,a[1]=1,a[2]=0,a[3]=1.a[4]=2,a[5]=1,a[6]=2。
观察可得1~3是一个可行的子串(不包括1)
1~5同样可行(不包括1)
也就是说,当他们对应的a数组值相等时,中间的串必定可行,因为中间的串没有引起值的变化,那么G和R相等。
那接下来我们该怎么做呢?
我们可以用2个for循环枚举数组a,找出值相等并且下标相差最大的两个点即为最大子串,但这样复杂度过高。
O(n)做法
我们以DP的角度考虑一个优解,使得这个过程能在线性时间内完成。如对于可行的长度为2的子串,我们只需要记录出现最早的长度为2的下标和出现最晚的下标即可。这里结合代码理解:
for(int i=0;i<str1.length();i++)
{
if(str1[i]=='G')
a[i+1]=a[i]+1;//计算a数组的值
else
a[i+1]=a[i]-1;
dp[a[i+1][1]=min(dp[a[i+1]][1],i+1);//记录最早
dp[a[i+1]][2]=max(dp[a[i+1]][2],i+1);//记录最晚
}
但是新的问题又来了,a[i+1]可能是负数,数组可没有负数的下标!其实这并不难,我们把dp的第一维扩大一倍,把中间的下标当作原来的下标零来使用,像这样:
//maxn=10000007
for(int i=0;i<str1.length();i++)
{
if(str1[i]=='G')
a[i+1]=a[i]+1;
else
a[i+1]=a[i]-1;
dp[a[i+1]+maxn+1][1]=min(dp[a[i+1]+maxn+1][1],i+1);
dp[a[i+1]+maxn+1][2]=max(dp[a[i+1]+maxn+1][2],i+1);
}
完整代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1000009;
int a[2*maxn];
string str1;
int dp[maxn*2+9][3];
int main()
{
cin>>str1;
for(int i=0;i<=maxn*2-5;i++)
dp[i][1]=100000000;//为min作预处理
dp[maxn+1][1]=0;//这里可以把maxn+1看作原来的下标0
for(int i=0;i<str1.length();i++)
{
if(str1[i]=='G')
a[i+1]=a[i]+1;
else
a[i+1]=a[i]-1;
dp[a[i+1]+maxn+1][1]=min(dp[a[i+1]+maxn+1][1],i+1);
dp[a[i+1]+maxn+1][2]=max(dp[a[i+1]+maxn+1][2],i+1);
}
int sumn=0;
for(int i=0;i<=maxn+str1.length();i++)//注意,从下标0开始
sumn=max(sumn,dp[i][2]-dp[i][1]);
cout<<sumn;
}
感谢dalao过目!
前缀和(P2697 宝石串)的更多相关文章
- Luogu P1114 “非常男女”计划/Luogu P2697 宝石串
Luogu P1114 "非常男女"计划/Luogu P2697 宝石串 (感觉我最近很爱做双倍经验的题啊) 使$d$等于第$i$个位置男生数(绿宝石数)减女生数(红宝石数)的差值 ...
- 洛谷 P2697 宝石串
题目传送门 解题思路: 将红色的设置为-1,绿色的为1,统计前缀和sum,如果sum[i] == sum[j],则说明i~j是一个稳定的区间 因为答案要求最大,所以我们要记录每个sum值的最左端点(也 ...
- HDU 1358 (所有前缀中的周期串) Period
题意: 给出一个字符串,在所有长度大于1的前缀中,求所有的周期至少为2的周期串,并输出一个周期的长度以及周期的次数. 分析: 有了上一题 HDU 3746 的铺垫,这道题就很容易解决了 把next求出 ...
- HDU 6153 A Secret 套路,求解前缀在本串中出现的次数
http://acm.hdu.edu.cn/showproblem.php?pid=6153 首先相当于翻转两个串,然后求s2前缀在s1中出现的次数. 这是一个套路啦 首先把两个串结合起来,中间加一个 ...
- Simpsons’ Hidden Talents - HDU 2594(求相同的前缀后缀)
题目大意:给你两个字符串,找出一个最大的子串,这个子串要是前面串的前缀并且是后面串的后缀........... 分析:next的简单运用吧,可以把两个串进行合并,中间加一个不能被匹配的字符,然后求 ...
- 2015 UESTC Training for Search Algorithm & String - M - Palindromic String【Manacher回文串】
O(n)的复杂度求回文串:Manacher算法 定义一个回文值,字符串S是K重回文串,当且仅当S是回文串,且其长度为⌊N/2⌋的前缀和长度为⌊N/2⌋的后缀是K−1重回文串 现在给一个2*10^6长度 ...
- 「BZOJ 4502」串
「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...
- hdu3336 KMP + DP 前缀数组出现的次数
题意: 给你一个串,问你他的所有前缀子串在本串中的出现次数,注释:abc的前缀子串是 a ab abc; 思路: 还是利用了next数组,先对子串求出next数组,再开一个数组d ...
- [51nod1587]半现串
将s所有长度为d/2的子串放进ac自动机中,直接匹配就可以判定半现串了再对其做一个差分,询问一个前缀的半现串个数,在ac自动机上数位dp,f[i][j][0/1]表示走了i步(i位的字符串),走到节点 ...
随机推荐
- alg-最长公共子序列
class Solution { public: std::string LongestCommonSubsequence(const std::string& s1, const std:: ...
- PLSQL Developer 中文乱码踩坑记
环境 操作系统版本: Windows 7 PL/SQL 版本: 12.0.1.1814 原因 由于 Oracle 服务器端和客户端字符集编码不一致引起的. 注意点 写在最前面,减少踩坑!!! 网上教程 ...
- 学会这项python技能,就再也不怕孩子偷偷打游戏了
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:鸟哥 PS:如果想了解更多关于python的应用,可以私信小编,资料 ...
- D - Catch That Cow BFS
农夫知道一头牛的位置,想要抓住它.农夫和牛都于数轴上 ,农夫起始位于点 N(0<=N<=100000) ,牛位于点 K(0<=K<=100000) .农夫有两种移动方式: 1. ...
- lua 逻辑运算 and, or, not
这边并非说lua低级,为了方便区分才这么写的. 高级语言中的逻辑运算符是&&,||,! a&&b : 当a和b都为真, 结果返回为真,当a或者b有一个为假,结果返回为假 ...
- google protobuf c++ 反射
const Descriptor *desc = DescriptorPool::generated_pool()->FindMessageTypeByName(msg_name); asser ...
- python3-邮件发送-不同格式
0x00 邮件格式 要发邮件,总要先了解邮件格式吧,这里指的是邮件的各个部分与python中SMTP所对应的一些必须的格式 0x01 简单发送邮件格式如下: import smtplib from e ...
- 【高频 Redis 面试题】Redis 事务是否具备原子性?
一.Redis 事务的实现原理 一个事务从开始到结束通常会经历以下三个阶段: 1.事务开始 客户端发送 MULTI 命令,服务器执行 MULTI 命令逻辑. 服务器会在客户端状态(redisClien ...
- s3cmd s3命令行工具
Amazon S3 Tools: Command Line S3 Client Software and S3 Backup 官方网站
- 高德地图首席科学家任小枫QA答疑汇总丨视觉+地图技术有哪些新玩法?
上周,阿里巴巴高德地图首席科学家任小枫在#大咖学长云对话#的在线直播活动上就计算机视觉相关技术发展以及在地图出行领域的应用与大家做技术交流,直播间互动火爆,尤其在QA环节,学弟学妹们纷纷就感兴趣的视觉 ...