logo AlgoBeat OnlineJudge
登录 注册

相思 题解

作者: AlgoBeat 官方账号  ·  发布于 2026-06-07 8:41:20
已通过

Burnside 先手从区间 中选一个整数 ,Edisnrub 后手从区间 中选一个整数 。 若 是合数则 Burnside 胜,否则 Edisnrub 胜。双方都采取最优策略,问谁必胜。


关键转化

· 后手 Edisnrub 在知道 的情况下选择 ,她的目标是让 为质数(如果可能的话)。 · 先手 Burnside 的目标是选择一个 ,使得 无论 Edisnrub 选哪个 都是合数。

换句话说,Burnside 胜当且仅当存在某个 ,使得对于 所有 都是合数。 等价地:对于某个 ,区间 内的所有整数都是合数。

若不存在这样的 ,则 Edisnrub 总能针对 Burnside 选的 找到一个 使得和为质数,因此 Edisnrub 胜。


问题重述

记:

· 为后手可选数字的个数。 · 固定 后, 是一个长度为 的连续整数区间:

我们要判断是否存在 ,使得区间 中 全部是合数。

若存在,输出 "Burnside";否则输出 "Edisnrub"。


数据范围与预处理

,因此 的最大值为

我们可以用 欧拉筛 或 埃氏筛 预处理 内的质数表,然后标记每个数是否为合数。

为了快速判断一个区间是否全为合数,我们对合数数组做 前缀和:

· comp[i] = 1 若 是合数,否则 0。 · pref[i] = sum_{k=2}^{i} comp[k]。

那么区间 内合数的个数为 pref[b] - pref[a-1]。若该值等于区间长度 ,则全为合数。


算法步骤

  1. 读入
  2. 计算
  3. 确定需要判定的区间起点范围: 对于 ,对应区间为 ,其起点范围为
  4. 筛出 内的质数,得到合数标记数组,并计算前缀和。
  5. 遍历起点 start 从 l1+l2 到 r1+l2: · 区间终点 end = start + L - 1。 · 检查该区间是否全部为合数:pref[end] - pref[start-1] == L。 · 若找到这样的区间,输出 "Burnside" 并结束。
  6. 若循环结束未找到,输出 "Edisnrub"。

复杂度分析

· 质数筛:,非常快。 · 前缀和:。 · 判定循环:最坏 次,每次 。 · 总复杂度:,完全可行。


正确性说明

· 若存在一个全合数区间,则 Burnside 选对应的 ,Edisnrub 无论如何选 都会得到合数,Burnside 胜。 · 若不存在这样的区间,则对于 Burnside 选的任意 ,区间 中至少有一个质数。Edisnrub 可以选择对应的 使得和为质数,从而获胜。 · 由于双方都采取最优策略,上述推理是完备的。


代码实现(C++)

#include <iostream>
#include <vector>
using namespace std;

const int MAXN = 200000;

int main() {
    int l1, r1, l2, r2;
    cin >> l1 >> r1 >> l2 >> r2;

    int L = r2 - l2 + 1;
    int max_sum = r1 + r2;

    // 筛法求质数
    vector<bool> is_prime(max_sum + 1, true);
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i * i <= max_sum; ++i) {
        if (is_prime[i]) {
            for (int j = i * i; j <= max_sum; j += i)
                is_prime[j] = false;
        }
    }

    // 合数标记 + 前缀和
    vector<int> comp(max_sum + 1, 0);
    for (int i = 2; i <= max_sum; ++i)
        if (!is_prime[i]) comp[i] = 1;

    vector<int> pref(max_sum + 1, 0);
    for (int i = 2; i <= max_sum; ++i)
        pref[i] = pref[i-1] + comp[i];

    // 枚举区间起点
    for (int start = l1 + l2; start <= r1 + l2; ++start) {
        int end = start + L - 1;
        if (end > max_sum) continue;   // 防止越界(实际上 end <= r1+r2 恒成立)
        if (pref[end] - pref[start-1] == L) {
            cout << "Burnside" << endl;
            return 0;
        }
    }

    cout << "Edisnrub" << endl;
    return 0;
}

样例验证

输入:1 2 3 4

· · 枚举 : · :区间 ,含质数 5 → 否 · :区间 ,含质数 5 → 否 · 无全合数区间 → 输出 "Edisnrub",符合样例。


小结

本题本质是 区间全合数判定,通过质数筛 + 前缀和可以高效解决。注意边界处理,以及筛法范围取到 即可。

暂无评论

登录 后即可评论。