题解:AtCoder AT_awc0130_a The Fate of the Vote

【题目来源】

AtCoder:A - The Fate of the Vote

【题目描述】

Takahashi and Aoki are candidates in a student council president election.

\(N\) students (student \(1\), student \(2\), \(\ldots\), student \(N\)) are the voters in this election, and each student initially supports exactly one of the two candidates. The initial support of each student is given by a string \(S\): if the \(i\)-th character of \(S\) is T, then student \(i\) supports Takahashi; if it is A, then student \(i\) supports Aoki. In the initial state, both candidates have at least one supporter.

Prior to the election, \(M\) speeches are given in order from the 1st to the \(M\)-th. In the \(i\)-th speech (\(1 \leq i \leq M\)), student \(R_i\) is persuaded and their support switches to the opposite candidate. That is, if they currently support Takahashi, they switch to supporting Aoki, and if they currently support Aoki, they switch to supporting Takahashi. Note that the same student may be specified in multiple speeches.

Immediately after each speech, it is checked whether either candidate has \(0\) supporters. If a candidate has \(0\) supporters, that candidate withdraws from the race, and the other candidate's victory is confirmed. Once a victory is confirmed, no further speeches are given. Note that this check is performed only immediately after each speech, and no check is performed on the initial state.

If a victory is confirmed before all \(M\) speeches are completed, output the number of the speech at which it was confirmed. That is, if the victory is confirmed immediately after the \(i\)-th speech, output \(i\). If both candidates still have supporters after all \(M\) speeches have been completed, output \(-1\).

高橋和青木是学生会长选举的候选人。

\(N\) 名学生(学生 \(1\)、学生 \(2\)\(\ldots\)、学生 \(N\))是这次选举的投票者,每名学生最初恰好支持两位候选人中的一位。每名学生的初始支持情况由字符串 \(S\) 给出:如果 \(S\) 的第 \(i\) 个字符是 T,则学生 \(i\) 支持高橋;如果是 A,则学生 \(i\) 支持青木。在初始状态下,两位候选人都至少有一名支持者。

选举前,将进行 \(M\) 场演讲,按第 \(1\) 场到第 \(M\) 场的顺序进行。在第 \(i\) 场演讲(\(1 \leq i \leq M\))中,学生 \(R_i\) 被说服,其支持转向另一位候选人。也就是说,如果他们当前支持高橋,则转而支持青木;如果他们当前支持青木,则转而支持高橋。注意,同一名学生可能在多场演讲中被指定。

每场演讲结束后,立即检查是否有候选人的支持者人数变为 \(0\)。如果有候选人的支持者人数为 \(0\),则该候选人退出竞选,另一位候选人的胜利即被确认。一旦胜利被确认,不再进行后续演讲。注意,此检查仅在每场演讲结束后进行,初始状态不进行检查。

如果在所有 \(M\) 场演讲完成之前就已确认胜利,输出确认胜利时的演讲编号。也就是说,如果在第 \(i\) 场演讲结束后确认胜利,输出 \(i\)。如果所有 \(M\) 场演讲结束后两位候选人仍有支持者,输出 \(-1\)

【输入】

\(N\) \(M\)
\(S\)
\(R_1\)
\(R_2\)
\(\vdots\)
\(R_M\)

  • The first line contains an integer \(N\) representing the number of students and an integer \(M\) representing the number of speeches, separated by a space.
  • The second line contains a string \(S\) of length \(N\) representing the initial support of each student.
  • The \((2 + i)\)-th line (\(1 \leq i \leq M\)) contains \(R_i\), the number of the student whose support is changed in the \(i\)-th speech.

【输出】

If a victory is confirmed before all \(M\) speeches are completed, output the number of the speech at which it was confirmed, on a single line. If both candidates still have supporters after all \(M\) speeches have been completed, output \(-1\) on a single line.

【输入样例】

4 4
TTAA
1
2
3
4

【输出样例】

2

【核心思想】

  1. 问题分析:给定 \(n\) 个学生,每人初始支持高橋(T)或青木(A),以及 \(m\) 场演讲。每场演讲说服一个学生改变支持对象(TA)。当某位候选人的支持者人数变为 \(0\) 时,另一位候选人立即获胜。求获胜确认的演讲编号,若 \(m\) 场后仍未分胜负则输出 \(-1\)。这是一个直接模拟 + 实时计数问题,关键在于用 map 维护两方人数,并在每次翻转后检查是否有方人数归零。

  2. 算法选择

    • 直接模拟:按顺序处理每场演讲,实时更新学生支持状态和两方人数
    • 实时胜负判定:每次翻转后检查被移出方的支持者是否变为 \(0\),若为零则立即输出当前演讲编号
  3. 关键步骤

    • 初始化:读入 \(n, m\) 和初始支持字符串 \(s\),统计初始两方人数存入 mp[0](青木)和 mp[1](高橋)
    • 模拟每场演讲\(i\)\(1\)\(m\)):
      • 读入被说服学生编号 \(x\)
      • mp[a[x]]--:将该学生从当前支持方移除
      • 胜负检查:若 mp[a[x]] == 0,输出 \(i\) 并结束程序
      • a[x] ^= 1:翻转支持对象(\(0 \leftrightarrow 1\)
      • mp[a[x]]++:将该学生加入新支持方
    • 未分胜负:循环结束后输出 \(-1\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + m)\),初始化统计 \(O(n)\),每场演讲 \(O(1)\) 更新
    • 空间复杂度:\(O(n)\),存储学生支持状态数组 a[1..n]
  5. 实时计数模拟的核心思想

    • 状态翻转的原子性:每次演讲是一个完整的事务——移除旧支持、检查胜负、加入新支持,确保计数始终一致
    • 提前终止优化:一旦某方人数归零立即输出,无需模拟剩余演讲,最坏情况才遍历全部 \(m\)
    • 异或位运算简化翻转a[x] ^= 1 利用异或性质实现 \(0 \leftrightarrow 1\)\(O(1)\) 切换,避免条件分支
    • 计数器与数组的双向维护a[x] 记录个体状态,mp 聚合全局统计,两者同步更新保证一致性
    • 适用于"双阵营动态翻转 + 实时胜负判定"的模拟问题

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;    // 定义数组最大容量为200005
int n, m;                // n为学生人数,m为演讲场数
map<int, int> mp;        // mp[0]记录支持青木(Aoki)的学生人数,mp[1]记录支持高橋(Takahashi)的学生人数
int a[N];                // a[i]记录第i个学生当前支持的对象:0表示支持青木(A),1表示支持高橋(T)

int main()
{
    cin >> n >> m;       // 读入学生人数n和演讲场数m
    string s;            // s为初始支持情况字符串
    cin >> s;            // 读入初始支持字符串
    s = " " + s;         // 在字符串前添加空格,使下标从1开始,方便处理

    // 初始化:统计初始状态下每位学生的支持情况
    for (int i = 1; i <= n; i++)  // 遍历每个学生
    {
        if (s[i] == 'T')          // 如果第i个学生初始支持高橋
        {
            a[i] = 1;             // a[i]设为1,表示支持高橋
            mp[1]++;              // 高橋支持者人数加1
        }
        else                      // 如果第i个学生初始支持青木
        {
            a[i] = 0;             // a[i]设为0,表示支持青木
            mp[0]++;              // 青木支持者人数加1
        }
    }

    // 依次模拟每场演讲
    for (int i = 1; i <= m; i++)  // i为当前演讲的编号
    {
        int x;                    // x为第i场演讲中被说服的学生编号
        cin >> x;                 // 读入学生编号

        mp[a[x]]--;               // 将该学生从当前支持的候选人中移除(对应人数减1)
        // 检查移除后该候选人的支持者是否变为0
        if (mp[a[x]] == 0)        // 如果该候选人的支持者人数变为0
        {
            cout << i << endl;    // 输出当前演讲编号i,胜利在此时被确认
            return 0;             // 程序结束,不再进行后续演讲
        }

        a[x] ^= 1;                // 学生x改变支持对象:0变1,1变0(异或1实现翻转)
        mp[a[x]]++;               // 将该学生加入新的支持候选人(对应人数加1)
    }

    // 所有m场演讲结束后,两位候选人仍然都有支持者
    cout << -1 << endl;           // 输出-1,表示未能在演讲过程中确认胜利
    return 0;
}

【运行结果】

4 4
TTAA
1
2
3
4
2
posted @ 2026-08-10 12:23  团爸讲算法  阅读(6)  评论(0)    收藏  举报