洛谷P2697 宝石串

洛谷P2697 宝石串

题目链接


题目大意
给一个只有 \(\texttt{R}\)\(\texttt{G}\) 的字符串,求一个 \(\texttt{R}\)\(\texttt{G}\) 数量相同的区间,输出这个区间的最大长度。


题解
1. 暴力
把所有 \(\texttt{R}\) 标记为 \(1\),把所有 \(\texttt{G}\) 标记为 \(-1\),求一下前缀和数组 \(s\)
二重循环枚举左端点和右端点 \(i\)\(j\),如果 \(s_{i-1}=s_j\)(即 \(s_j-s_{i-1}=0\)),则说明当前区间为稳定区间。
如果当前区间为稳定区间,更新答案,最后输出最大答案即可。
时间复杂度为 \(\mathcal O (n^2)\)
2. 优化方案
由暴力的启发,我们可以用一个数组 \(m\) 记录每个前缀和第一次出现的位置,之后再遇到这个前缀和就会产生一个稳定区间。
由于前缀和可能为负数,所以把 \(m\) 数组下标加上该字符串的长度。
时间复杂度减小到 \(\mathcal O (n)\)


代码
\(\mathcal O (n^2)\) 暴力:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char t[1000005];
int a[1000005], s[1000005], ans;
int main()
{
    cin >> t;
    int n = strlen(t);
    for (int i = 1; i <= n; i++)
    {
        if (t[i - 1] == 'R')
        {
            a[i] = 1;
        }
        else if (t[i - 1] == 'G')
        {
            a[i] = -1;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        s[i] = a[i] + s[i - 1];
        if (s[i] == 0)
        {
            ans = max(ans, i);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = i + 1; j <= n; j += 2)
        {
            if (s[j] == s[i - 1])
            {
                ans = max(ans, j - i + 1);
            }
        }
    }
    cout << ans;
    return 0;
}

\(\mathcal O (n)\) 优化方案:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int s[1000005], a[1000005], m[1000005], ans;
char t[1000005];
int main()
{
    cin >> t;
    int n = strlen(t);
    for (int i = 0; i < n; i++)
    {
        if (t[i] == 'R')
        {
            a[i + 1] = 1;
        }
        else
        {
            a[i + 1] = -1;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        s[i] = s[i - 1] + a[i]; //预处理前缀和
    }
    for (int i = 1; i <= 2 * n + 2; i++)
    {
        m[i] = -1;
    }
    m[n + 1] = 0;
    for (int i = 1; i <= n; i++)
    {
        if (m[s[i] + n + 1] >= 0)
        {
            ans = max(ans, i - m[s[i] + n + 1]); //更新答案
        }
        else
        {
            m[s[i] + n + 1] = i; //记录该前缀和第一次出现的位置
        }
    }
    cout << ans;
    return 0;
}
posted @ 2021-01-24 19:32  cymrain07  阅读(158)  评论(0)    收藏  举报
\