• P2697 宝石串


    题目描述

    有一种宝石串,由绿宝石和红宝石串成,仅当绿宝石和红宝石数目相同的时候,宝石串才最为稳定,不易断裂。安安想知道从给定的宝石串中,可以截取一段最长的稳定的宝石串,有多少颗宝石组成。请你帮助他。

    绿宝石用‘G’表示,红宝石用‘R'表示。

    输入格式

    一行由GR组成的字符串

    输出格式

    最长的稳定的宝石串有多少颗宝石组成

    输入输出样例

    输入#1                                               输出#1

    GRGGRG                                          4

    数据范围:

    宝石数≤1000000

    思路:

    这道题需要使用前缀和算法。

    我们可以使用类似于最长括号匹配(P1944 蓝题)的思想。因为只有GR两种宝石,所以我们可以将字符转化为数字。设G表示的值为1R表示的值为-1,则原来的字符串就变成了一串数字串“1 -1 1 1 -1 1”。这时候,稳定的条件即从‘G'和’R'完全匹配,变成了1和-1相互匹配。

    接下来,我们要考虑什么条件能够说明宝石完全匹配。将'G'和'R'转化为1和-1有一个好处:这样如果我们将一个1和一个-1放在一起,组合而成的数的特点即为1+(-1)=0.

    这样思考之后,我们就可以维护这个数字串的前缀和数组:1 0 1 2 1 2。当在前缀和数组中,两个数的值相等,则说明宝石已经完全匹配。

    这样我们就有了写代码的思路:建立一个数组f,f[i]表示从第i块宝石往前推,所构成的稳定的宝石串的最大长度。而计算整个宝石串内稳定的串的最大长度,只需要对f数组取max即可。

    下面是代码:

     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 string s;
     5 int n,i,j,ans;
     6 int sum[1000005]={0},f[1000005]={0};
     7 int main(){
     8     cin>>s;
     9     n=s.length();
    10     for(i=1;i<=n;i++){
    11         if(s[i-1]=='G'){ //绿宝石代表1
    12             sum[i]=sum[i-1]+1;
    13         }else if(s[i-1]=='R'){ //红宝石代表-1
    14             sum[i]=sum[i-1]-1;
    15         }
    16     }
    17     ans=-99999;
    18     for(i=1;i<=n;i++) {
    19         for(j=i;j>=1;j--) {
    20             if(sum[i]==sum[j]) {
    21                 f[i]=i-j;
    22             }
    23         }
    24         if(ans<f[i]){
    25             ans=f[i];
    26         }
    27     }
    28     cout<<ans<<endl;
    29     return 0;
    30 }

    但是这份代码只能得40分。

    为什么?

    这份代码的问题在于它枚举的边界出现了错误

    我们来考虑,当数据为GGRRGR的时候,得到的对应的前缀和数组为:1 2 1 0 1 0.这样我们在运行程序的时候,得到的结果是4.但是,事实上,正确的答案很明显应该是6.这是为何呢?

    我们再一次看这份代码:

    这份代码的问题出在:我们的前缀和数组是从1开始维护的。但是我们并没有考虑这样一种情况:当我们的真实最长稳定序列是从头开始的时候,我们判断这个序列是否稳定应该依据于这个序列的尾结点sum值是否等于0.然而我们并没有存储这个‘0’,所以这种情况就被略过了。

    那么这个问题如何解决呢?只需要将sum[0]=0加入到枚举的范围中即可。

    下面是AC代码:

     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 string s;
     5 int n,i,j,ans;
     6 int sum[1000005]= {0},f[1000005]= {0};
     7 int main() {
     8     cin>>s;
     9     n=s.length();
    10     for(i=1; i<=n; i++) {
    11         if(s[i-1]=='G') { //绿宝石代表1
    12             sum[i]=sum[i-1]+1;
    13         } else if(s[i-1]=='R') { //红宝石代表-1
    14             sum[i]=sum[i-1]-1;
    15         }
    16     }
    17     ans=-99999;
    18     for(i=1; i<=n; i++) {
    19         for(j=i; j>=0; j--) {//枚举到0
    20             if(sum[i]==sum[j]) {
    21                 f[i]=i-j;
    22             }
    23         }
    24         if(ans<f[i]) {
    25             ans=f[i];
    26         }
    27     }
    28     cout<<ans<<endl;
    29     return 0;
    30 }
  • 相关阅读:
    C语言枚举类型使用简介
    C实现单链表(转)
    不同数据库数据类型
    Informix 常用命令
    工作了
    修改route使用有线/无线同时连接内外网
    Perl 时间函数
    Linux 系统命令
    SQL SERVER 触发器示例
    Informix 函数
  • 原文地址:https://www.cnblogs.com/qianr/p/13334450.html
Copyright © 2020-2023  润新知