前缀和(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位的字符串),走到节点 ...
随机推荐
- HBase Shell 十大花式玩儿法
前言:工欲善其事必先利其器,今天给大家介绍一下HBase Shell十大花式利器,在日常运维工作中,可以试着用起来. 1. 交互模式 也就是我们最常用到的Shell命令行的方式. $ hbase sh ...
- Atlas运行时资源不足报错 -bash: fork: retry: 资源暂时不可用 Out of system resources
目的:运行Atlas并使用Azkaban执行操作任务 环境:Centos 6 内存大小:12G 启动下面的任务后还剩内存将近5G 问题: 当mysql_to_hdfs_db和其他job同时运行时集群很 ...
- VCL安装有哪几种方法?
不是由Borland 提供的组件叫第三方组件: 就目前常见的各种形式的组件的安装方法介绍一下. 1.只有一个DCU文件的组件.DCU文件是编译好的单元文件,这样的组件是作者不想把源码公布.一般来说,作 ...
- HashMap主要方法源码分析(JDK1.8)
本篇从HashMap的put.get.remove方法入手,分析源码流程 (不涉及红黑树的具体算法) jkd1.8中HashMap的结构为数组.链表.红黑树的形式 (未转化红黑树时) (转 ...
- Java日期时间API系列30-----Jdk8中java.time包中的新的日期时间API类,减少时间精度方法性能比较和使用。
实际使用中,经常需要使用不同精确度的Date,比如保留到天 2020-04-23 00:00:00,保留到小时,保留到分钟,保留到秒等,常见的方法是通过格式化到指定精确度(比如:yyyy-MM-dd) ...
- [linux][MongoDB] mongodb学习(二):命令使用数据库
使用数据库 # 查看数据库 > show dbs admin 0.000GB local 0.000GB # 查看表(集合) > show tables # 删除集合 > db.us ...
- Java 多线程 -- lambda 表达式推导
jdk 8 开始 java 引入了lambda 表达式. lambda适用场景: 1.接口或父类 2.接口或父类只有一个方法 我们从多线程写法来推导一下: 1.外部类写法: package com.x ...
- 好用的反向代理工具NATAPP
这里推荐一个好用的反向代理工具NATAPP NATAPP1分钟快速新手图文教程 有免费的和付费的个人建议付费的,免费还需要身份证验证,付费版最低9元/月,看个人需求! 这里给个邀请码贴在这需要的话可以 ...
- liunx系统二进制包安装编译mysql数据库
liunx系统二进制包安装编译mysql数据库 # 解压二进制压缩包 [root@localhost ~]# tar xf mysql-5.5.32-linux2.6-x86_64.tar.gz -C ...
- JavaScript和php数组的定义
JavaScript: var arr=[值1,值2,值3]; //隐式创建 var arr=new Array(值1,值2,值3); //直接实例化 ...