第一次训练赛感受和题解

第一次训练赛感受和题解

感受

说实话,除了去年12月份的新生赛,这应该是我第二次打较为正式的比赛。总体而言,成绩不是很好但作为对算法和数据结构一无所知的菜鸡通过强行暴力还是AC了三道题。但是听了 ACMer 的官方题解后,我还是深深的感受到了自己在算法方面的不熟悉。为什么这么说呢?是因为即便是我自己写出来并且AC 的题,我也并不知道这道题背后蕴藏的是哪个算法,哪个知识点,所以可以说是并没有将自己所学到的不多的算法知识进行融会贯通和运用,革命尚未成功,同志仍需努力啊!!!

题解

A题:

括号王国的括号国王统领着一支军队,在这支军队中,每个人都有且只有一位长官,但一个人可能有多名手下。特别的,作为一国之君,括号国王没有长官。 现在,括号国王想要知道每一个人的长官都是谁,你能帮助他完成这个任务吗? 括号国王和他的军队通过一个仅含数字和括号的字符串来表示,每个数字会有零至多个括号,每个括号内的第一个数字都表示该人物的手下。 例如,字符串2(3(4))(1)表示2号的手下有3号和1号;3号的手下有4号;1号和4号没有手下。特别的,2号没有长官,说明2号就是括号国王。 请输出每个人的长官是谁。

Input

输入第一行为正整数n,表示括号王国一共有n个人(含国王)。保证正整数n不超过140000。 第二行为题目中所描述的字符串,串长保证不超过1000000,且严格按照题目描述中所说的格式。 保证字符串中,1~n的每个数字出现且仅出现一次。

Output

请输出一行n个非负整数,之中第i个数字表示编号为i的人物的长官是谁。 特别的,由于括号国王没有长官,请在括号国王处输出0。

Examples

Input

4
2(3(4))(1)

Output

2 0 2 3

Input

7
4(2)(5(3(6)(1))(7))

Output

3 4 5 0 4 3 5

分析:

这道题其实是一个字符串的判断问题,通过判断一串字符中的括号关系和数字来进行分析。首先说说我对这道题的看法和理解。我拿到这道题其实第一时间是简单的将数字认为是小于十的数字(即一位数)所以直接定义一个vector然后 getline ,通过记录是否遇到 ‘(’ 来判断谁是国王。但是第一次提交就遇到了数字可能大于十的障碍。于是想到了一个很基础的方法

​ 保存字符串中的数字:

x=10*x+(s[i]-’0’);

ps:即便是最后我想到了这个方法但是我的代码还是没有AC

这是并没有AC的错误代码(最后的错误原因好像是由于一个数据特别大的上限示例没有通过,可能是超时了)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
vector<int> king;//保存目前的国王/长官
int main()
{
    int n, i, a=0, b=0, ans[140000], len, y=0, x;
    char str[1000000];
    cin >> n;
    getchar();
    gets(str);//整体输入字符串
    len = strlen(str);
    for(i = 0;i < len;i++){
        y=0;
        if(str[i] == '('){
            a++;            //记录前括号(通过前括号可以判断谁是长官)
        }else if(str[i] == ')'){
            a--;            //记录后括号(通过后括号排除非长官数字)
        }else if(a == 0 && str[i] > '0' && str[i] <= '9'){

            for(x=i;str[x]>='0'&&str[x]<='9';x++){
                y=y*10+str[x]-'0';
            }
            // 这段代码是用来将字符串中的数字转移储存
            king[a] = y;  // 寻找并且记录国王
            ans[y] = 0;
        }else if(a == 1 && str[i] > '0' && str[i] <= '9'){
            for(x=i;str[x]>='0'&&str[x]<='9';x++){
                y=y*10+str[x]-'0';
            }
            ans[y] = king[a-1];
            king[a] = y;//其实这个条件分类与最后一个重复了,因为这两个条件都是用来寻找长官的,不论是隶属于国王的长官还是隶属于长官的长官
        }else{
            for(x=i;str[x]>='0'&&str[x]<='9';x++){
                y=y*10+str[x]-'0';
            }
            ans[y] = king[a-1];
            king[a] = y;
        }
    }
    for(i=1;i<n;i++){
        printf("%d ",ans[i]);//利用ans数组的角标记录每个人以及他说对应的长官,最后依次输出
    }
    printf("%d\n",ans[i]);//为了满足输出格式:前面的数据后面跟空格,最后一个数据后面加换行

}

但是,其实这道题并不是我这样傻傻的做的,其实它是一个:简单模拟+栈

具体内容是:先将字符串中的数字转换为数字,然后弄个存数字的栈,栈顶的数字表示当前最新的长官(类似与我代码中的king数组),此时遇到的数字,都归为栈顶数字的直属手下;当遇到右括号时弹出栈顶数字。

可以AC的标准代码:

#include <bits/stdc++.h>//包含所有头文件的头文件(不过好像有些judge平台不过这个)
using namespace std;
typedef long long LL;
const int maxn = 1000000 + 10;

int n, len;
char s[maxn];
stack<int> sta;//定义栈
int fa[maxn];

int main() {
    scanf("%d", &n);
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    int i = 1;
    while (i <= len) {
        if (s[i] >= '0' && s[i] <= '9') {
            int x = 0;
            while (i <= len && s[i] >= '0' && s[i] <= '9') {
                x = x * 10 + s[i] - '0';
                i++;
            }//将字符串转换为数字
            if (sta.empty())
                fa[x] = 0;//记录国王
            else
                fa[x] = sta.top();//将原来栈顶的数字记录在以现在这个数字作为角标的数组中
            sta.push(x);//将这个数字加入栈顶
        }
        if (s[i] == ')') sta.pop();//遇到后括号即弹出栈顶数字
        i++;
    }
    for (int i = 1; i <= n; i++) printf("%d%c", fa[i], i == n ? '\n' : ' ');//遍历答案数组并且输出
    return 0;
}

反思:首先,这个题我没有审清楚题意,忽略了字符串中转换为数字这一基本操作,其次就是自己对栈这一数据结构不够熟悉和熟练,像这种存在数据叠加归属的问题应该利用栈可以通过条件使得栈顶数字加入或者删除并且不影响栈下面的数字。

B题:

Jaehyun has a bead which consists of NN jewels arranged from left to right. Each jewel is in one of the three colors: Red, Blue, and Violet, which is represented as a single character R, B, V. As one of the committees in an important contest, Jaehyun wants to use it as a souvenir for some participant.

Jaehyun likes a bead with diverse colors, so he defines a bead beautiful if every adjacent jewel has different colors. For example, RBVBV is a beautiful bead because every adjacent jewel has a different color. V is a beautiful bead because it does not have adjacent pairs. However, RBBV is not a beautiful bead, because two Bs in the middle are adjacent in the string.

Not only Jaehyun likes a bead with diverse colors, but he likes a contest with diversity. This time, Jaehyun wants to make a bead that is also colorful to colorblind people. For convenience, we will only consider three kinds of people in this problem.

  • Non-colorblind people, who can tell all three colors.
  • Red-colorblind people (Protanopia), who can't tell apart red and violet: They consider violet jewels as red jewels.
  • Blue-colorblind people (Tritanopia), who can't tell apart blue and violet: They consider violet jewels as blue jewels.

In this case, the string RVB is colorful for non-colorblind people, but it is not colorful for red-colorblind people as red and violet jewels are adjacent, and it is also not colorful for blue-colorblind people as violet and blue jewels are adjacent.

Jaehyun wants to pick some contiguous part of the bead and cut it out to give as a souvenir. The part Jaehyun cuts should be colorful to all three kinds of people. Note that, if the whole bead is beautiful, then Jaehyun does not necessarily cut it out, but just give the whole bead. What is the length of the longest bead he can give?

Input

The first line contains an integer NN, denoting the length of the bead. (1≤N≤2500001≤N≤250000)

The next line contains string of length NN, where every character is either R, B, or V.

Output

Print the maximum possible length of contiguous beads, which is colorful for all three kinds of people.

Examples

Input

4
VRRB

Output

2

Input

5
RBBRR

Output

2

题意:简单的说就是现在会给你一串带有V,R,B三种颜色的珠子,但是现在有三种人:一种可以分清楚三种颜色,一种会将R和V弄混,最后一种会将B和V弄混,现在给你输入珠子的个数和一串表示珠子颜色的字符串,请你输出不会被三个人弄混的最长的珠子数。

我拿到这道题就知道R和B相邻对于三个人而言都是满足条件的,所以如果前一个珠子是R,则下一个珠子只有是B才能满足题设条件;如果前一个珠子是B,则下一个珠子只能是R才能满足条件;但如果前一个珠子是R,那么不论下一个珠子是什么颜色都无法满足题设。

那么我就想,将字符串中的每一个字符一个一个的输入,并且在输入后与前一个进行判断,如果符合要求则珠子数++,否则将珠子数归1;

我的代码(这个题是AC了的):

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>

using namespace std;
vector<char> list;//因为不知道具体的数组开多大所以用vector
int main()
{
    int N, i, ans=1, end=1;
    char c;
    cin >> N;
    getchar();
    for(i = 0;i <N;i++){
        cin >> c;//一个一个输入字符
        list.push_back(c);//将字符加入数组
        if(i!=0){
            if(list[i-1]=='R'){
                if(list[i]=='B'){
                    ans++;
                }else{
                    ans = 1;
                }
            }else if(list[i-1]=='B'){
                if(list[i]=='R'){
                    ans++;
                }else{//这个是前一个珠子为V的情况
                    ans = 1;
                }
            }else{
                ans = 1;
            }
        }
        if(ans > end){
            end = ans;
        }
    }
cout << end << endl;
}

dalao们的题解说这道题是用双指针/dp去解,

双指针:

众所周知,n个字符组成的子串是n^2级别的,所以要想方设法的避免枚举所有区间;

可以使用双指针(也叫做滑动窗口)即令left,right初始为1,[left,right]确定的区间总满足题设条件,如果right右移一格之后得到的 [left,right]区间仍然满足条件,右移right,否则右移left,在移动过程中,right-left+1的最大值就是答案;由于每次一定移动两个指针之一,操作次数不超过2n,是线性的。

#include <bits/stdc++.h>
using namespace std;
char a[300000];
int n, ans;
bool ok(int pre, int aft) {
    if (a[pre] == a[aft])
        return false;
    if (a[pre] == 'V' || a[aft] == 'V') {
        return false;
    }
    return true;
}
int main() {
    cin >> n;
    cin >> (a + 1);
    ans = 1;
    for (int l = 1, r = 1; r < n && l < n;) {
        if (ok(r, r + 1)) {
            r++;
        } else {
            l = r + 1;
            r = r + 1;
        }
        ans = max(ans, r - l + 1);
    }
    cout << ans << endl;
    return 0;
}

dp:

用dp做,dp[i]表示以i结尾的满足条件的区间的最长长度

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 300000 + 10;

int n;
char s[maxn];
int f[maxn];

int main() {
    scanf("%d", &n);
    scanf("%s", s + 1);
    f[1] = 1;
    for (int i = 2; i <= n; i++) {
        if ((s[i] == 'R' && s[i - 1] == 'B') || (s[i] == 'B' && s[i - 1] == 'R'))
            f[i] = f[i - 1] + 1;
        else
            f[i] = 1;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) ans = max(ans, f[i]);
    printf("%d\n", ans);
    return 0;
}
posted @ 2020-02-17 17:55  TOBE_ACODER  阅读(154)  评论(0编辑  收藏  举报