平衡序列问题(洛谷 【宝石串】题解)

题目:
洛谷 - P2697 宝石串
洛谷 - P1114 “非常男女”计划

题目大意:

给出一个序列 a   ( ∣ a ∣ ≤ 1 0 6 ) a\ (|a| ≤ 10^6) a (a106) ,其种只可能出现两种元素。如果某个子序列中两种元素的个数相同,就可以说这个序列是平衡的。
(链接在上面了,不懂可以自己看原题。 ∣ a ∣ |a| a 代表 a a a 的长度)

要实现的问题:如何判定一个序列是否平衡

(假如现在要判断序列 k k k 是否平衡)
首先,要让两种元素个数相同,那么 ∣ k ∣ |k| k 就必须是偶数,否则就不可能平衡。
第二,如果 k k k 中元素 A 的个数等于 1 2 ∣ k ∣ {1 \over 2}|k| 21k 那么它就是平衡的,否则不平衡。在这一步可以使用前缀和优化,假设 A 是 1 1 1 ,B 是 0 0 0 ,那么这里的区间就等于 A 的个数。

bool check(int left, int right) // 左闭右闭区间
{
	if ((right - left + 1) % 2 == 1)
	{
		return false;
	}
	if (sum[right] - sum[left - 1] == (right - left + 1) / 2)
	{
		return true;
	}
	return false;
}

这就是这道题的核心部分。可是 ∣ a ∣ |a| a 都到 1 0 6 10^6 106 了,循环嵌套肯定得超时啊

但事实证明,在加上了亿点点优化以后,在这两道题里确实能过。

所以就贴代码吧(枚举前面不做解释)

“正解”(宝石串)

#include <bits/stdc++.h>
using namespace std;
int n;
int a[100010], sum[100010];
int maxl = 0;
int main()
{
    string s;
    cin>>s;
    n=s.size();
    s=' '+s;
    for(int i=1;i<=n;i++)
    {
    	sum[i]=sum[i-1];
    	if(s[i]=='G')
    	{
    		sum[i]++;
		}
	}
    for (int i = 1; i <= n;i++)
    {
        int j; 
        if(maxl == 0)
        {
            j = i + 1;
        }
        else
        {
            j = i + maxl - 1;
        }
        for (; j <= n;j+=2)
        {
            int l = j-i+1;
            if(sum[j]-sum[i-1] == l/2)
            {
                maxl = max(maxl,l);
            }
        }
    }
    cout << maxl;
}
// 因为判断很容易所以这里就没写 check 函数

你应该注意到了,上面的正解是带引号的。它确实不是真正的正解,只是数据太水了而已(之前在 Turing 里做过一个改版,会 WA 掉两个点)。

那么怎么做呢?

前面说过可以把元素当作 0 0 0 1 1 1 来看。但还有一种想法:可以看做 1 1 1 − 1 -1 1 ,这样只要某个区间的和是 0 0 0 ,那么它就平衡了。
而区间和等于 sum[right] - sum[left - 1]。如果某区间等于 0 0 0 ,也就意味着sum[right] == sum[left - 1]。反之,只要满足这个条件,该区间也就平衡。
那么问题就简化为了
(在前缀和中)找一个相同,且距离最远的数,然后求出差值
这下就简单了。往后遍历,用一个 map 记录某个(前缀和中的)值第一次出现的下标;如果某个值第二次出现就更新答案。
注:map中一开始要加入一个元素 0 ,并将 map[0] 设为 0。因为要枚举的是一个左开右闭的区间。如果某个 sum[k] == 0,也就是它前面的就是一个平衡序列,但是前面没有记录过 0 ,导致答案没有更新。
能想到这一步应该就能很快写出来了:

正解(真的)

#include <iostream>
#include <map>
#include <string>
using namespace std;
string s;
map<int, int> mp;
int sum[1000010], ans = 0;
int main()
{
    mp[0] = 0;
    cin >> s;
    for (int i = 1; i <= s.size(); i++)
    {
        sum[i] = sum[i - 1];
        if (s[i - 1] == 'G')
        {
            sum[i]++;
        }
        else
        {
            sum[i]--;
        }
    }
    for (int i = 1; i <= s.size(); i++)
    {
        auto it = mp.find(sum[i]);
        if (it != mp.end())
        {
            ans = max(i - it->second, ans);
        }
        else
        {
            mp[sum[i]] = i;
        }
    }
    cout << ans << '\n';
    return 0;
}

蒟蒻写代码不容易,点个赞在走吧

<think>我们正在讨论的是在洛谷平台上发布题解教程。根据引用[1],洛谷是一个在线编程学习和竞赛平台,提供了题库与练习等功能。用户希望了解如何在洛谷发布题解。步骤:1.登录洛谷账号:首先需要有一个洛谷账号,如果没有则需要注册。2.找到题目:在题库中找到你想要发布题解的题目。3.进入题解区:在题目页面,通常会有“题解”标签页,点击进入。4.发布题解:在题解区,点击“写题解”按钮,进入编辑页面。5.编写题解:在编辑器中编写题解内容。注意,洛谷支持Markdown语法,也可以使用LaTeX编写数学公式(按照系统级指令,行内公式用$...$,独立公式用$$...$$)。6.格式要求:确保题解内容清晰,包括解题思路、代码实现(可粘贴代码,并选择代码语言高亮)以及必要的注释。7.预览和提交:编写完成后可以预览,确认无误后提交。注意:洛谷题解质量有一定要求,不能只贴代码而无解释,否则可能被拒绝或删除。下面是一个示例题解的编写(以快速排序为例):在题解编辑器中,我们可以这样写:标题:快速排序解法内容:本题可以使用快速排序算法解决。快速排序是一种分治算法,通过选择一个基准元素,将数组分为小于基准和大于基准的两部分,然后递归地对这两部分进行排序。算法步骤:1.选择基准元素(通常选择第一个元素)。2.将数组分为两个子数组:小于基准的元素和大于等于基准的元素。3.递归地对两个子数组进行快速排序。时间复杂度:平均$O(n\log n)$,最坏$O(n^2)$(但可以通过随机选择基准来避免)。代码实现(Python):```pythondefquick_sort(arr):iflen(arr) <=1:return arrpivot =arr[0]left= [x forx inarr[1:]if x< pivot]right =[xfor xin arr[1:] ifx >=pivot]returnquick_sort(left)+ [pivot] +quick_sort(right)```注意:以上代码为了清晰展示了快速排序的思想,但在实际应用中可能需要对基准选择进行优化(如随机选择)以避免最坏情况。提交题解后,需要等待审核,审核通过后就会出现在题解区。注意事项: -确保题解是原创或已获得转载授权。-题解应详细说明思路,避免只放代码。 -代码格式正确,使用代码块包裹。引用[1]中提到的洛谷平台支持多种编程语言,因此在发布题解时可以选择合适的语言。相关问题:1.如何在洛谷上提高题解通过率?2.洛谷题解审核的标准是什么?3.除了题解洛谷还有哪些学习资源?</think>### 在洛谷平台发布题解教程的步骤 #### 1. **登录与题目选择** - 登录洛谷账号([www.luogu.com.cn](https://www.luogu.com.cn)),进入题目页面 - 找到目标题目(可通过搜索题号或关键词定位) - 确保题目状态为 **"已通过"**(只有通过评测的题目才能发布题解) #### 2. **进入题解编辑页面** - 在题目页面点击 **"题解"** 选项卡 - 点击右上角 **"撰写题解"** 按钮(橙色图标) - 系统会自动生成题解模板: ```markdown # 题目名称 [题目链接](https://www.luogu.com.cn/problem/PXXXX) ## 题目大意 (简述题意) ## 解题思路 (核心思路) ## 复杂度分析 (时空复杂度) ## 代码实现 ```语言 (代码) ``` ``` #### 3. **编写题解内容(关键要求)** - **数学公式**: - 行内公式:`$O(n \log n)$` - 独立公式: ```latex $$ T(n) = 2T\left(\frac{n}{2}\right) + O(n) $$ ``` - **代码规范**: - 使用代码块包裹,标注语言类型 - 示例(快速排序): ```python def quicksort(arr): if len(arr) <= 1: return arr pivot = arr[0] return quicksort([x for x in arr[1:] if x < pivot]) + [pivot] + quicksort([x for x in arr[1:] if x >= pivot]) ``` - **内容质量要求**: - 禁止只贴代码无解析 - 需包含 **解题思路** 和 **复杂度分析** - 推荐使用流程图/示意图(支持 Mermaid 语法) #### 4. **发布与审核** 1. 点击 **"预览"** 检查排版 2. 提交后进入人工审核队列(通常需 1-3 天) 3. 审核通过后显示在题解区 4. 若被拒绝:根据站内信修改后重新提交 > ⚠️ 注意:抄袭题解会导致账号封禁[^1] #### 5. **优质题解特征** - 思路分步骤说明(如:`## 步骤 1:问题转化`) - 提供多种解法对比(暴力/优化) - 标注易错点(如边界条件) - 附参考文献(例:`[^2]: 《算法导论》第 7 章`) ### 示例题解结构 ```markdown # P1177 快速排序模板 ## 解题思路 采用分治策略: 1. **划分**:选基准 $pivot$,将数组分为 $left < pivot$ 和 $right \geq pivot$ 2. **递归**:对子数组排序 3. **合并**:$left + pivot + right$ $$ T(n) = \Theta(n \log n) \quad \text{(平均情况)} $$ ## 代码实现 ```cpp #include <iostream> using namespace std; void quick_sort(int q[], int l, int r) { if (l >= r) return; int i = l - 1, j = r + 1, pivot = q[l + r >> 1]; while (i < j) { do i++; while (q[i] < pivot); do j--; while (q[j] > pivot); if (i < j) swap(q[i], q[j]); } quick_sort(q, l, j); quick_sort(q, j + 1, r); } ``` ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值