1 条题解
-
0
本题为 CF 2040A - Game of Division。
下面给出详细题解。
题目大意
两个人玩游戏。给定长度为 的数组 和一个整数 。
- 第一个人先选一个下标 ,这一选定的数将作为“基准数”。
- 第二个人从剩下的数中选一个下标 。
- 如果 能被 整除,则第二个人赢;否则第一个人赢。
问:第一个人是否存在一种选法,使得无论第二个人怎么选,他都能赢。
如果存在,输出YES和选中的下标;否则输出NO。
数学转化
我们知道:
[ |a_i - a_j| \text{ 能被 } k \text{ 整除} \iff a_i \equiv a_j \pmod{k} ]
所以第二个人赢的条件是:他能在剩下的数中找到一个与第一个人选的数模 同余的数。
反之,第一个人要赢,必须保证他所选的数在模 的剩余类中,是唯一的一个。
因为第二个人会选同一个剩余类里的数(只要存在),从而获胜。
算法步骤
- 对每个数 计算 ,并按模值分组。
- 查找是否存在某个模值 ,使得该组只有一个元素。
- 如果找到,则第一个人选那个下标,输出
YES和下标(标程里输出 就是该元素在输入中的顺序下标,注意输入下标从 1 开始)。 - 如果所有模值分组大小都不为 1,则输出
NO。
代码分析(对应你给的标程)
#include <bits/stdc++.h> using namespace std; int main() { int tt; cin >> tt; while (tt--) { int n, k; cin >> n >> k; vector<vector<int>> b(k); // b[r] 存放模 k 等于 r 的所有元素的下标 for (int i = 1; i <= n; i++) { int x; cin >> x; b[x % k].push_back(i); } int res = -1; for (int i = 0; i < k; i++) { if ((int)b[i].size() == 1) { res = b[i][0]; break; } } if (res == -1) { cout << "NO" << endl; } else { cout << "YES" << endl << res << endl; } } return 0; }
举例验证
例:
数组:模 2 分组:
- 余 0:
- 余 1:
每组大小都是 2,不存在大小为 1 的组 → 输出
NO。
例:
数组:模 3 分组:
- 余 0:
- 余 1:(两个元素)
- 余 2:(一个元素)
找到余 2 组大小为 1 → 输出
YES和下标 3(注意输入:1 下标1,2 下标2,4 下标3)。
复杂度
- 时间:
- 空间:
- 适合 较大但总和有限制的题目设定。
- 1
信息
- ID
- 6995
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者