牛客多校 A 题题解
牛客多校 8 - A
Haitang and Game
Given a set \(\textstyle S\), dXqwq and Haitang take turns performing the following operations, with dXqwq going first:
-
Find a pair \(\textstyle (x,y)\) such that \(\textstyle x,y\in S\) and \(\textstyle \gcd(x,y)\notin S\).
-
Insert \(\textstyle \gcd(x,y)\) into \(\textstyle S\).
The player who cannot make a move loses the game. You need to output the winner when both players play optimally.
Each test contains multiple test cases. The first line contains an integer \(\textstyle T\) (\(\textstyle 1\leq T\leq 20\)) — the number of test cases. The description of the test cases follows.
The first line of each test case contains a single integer \(\textstyle n\) (\(\textstyle 1\leq n\leq 10^5\)) — the size of set \(\textstyle S\).
The second line contains \(\textstyle n\) integers \(\textstyle a_1,a_2,\cdots,a_n\) (\(\textstyle 1\leq a_1<a_2<\cdots<a_n\leq 10^5\)) — the elements of set \(\textstyle S\).
解题思路:
考场上这题没优化好导致 \(95.46\) 的样例通过,而最后 \(4.54\) 的样例被卡了,我真的服了
- 简单分析之后可以发现,无论两边最后怎么选,最后的形成的数列的个数是固定的,如果最后形成的数列的个数比原本的数列的个数增加奇数个,那么 \(dXqwq\) 胜利, 否则 \(Haitang\) 胜利.
- 而要怎么找出所有的可能插入的 \(gcd\) 呢? 首先,观察到数据范围在 $ 1\leq a \leq 10^5$ 的范围,我们可以开一个 \(bool\)类型的哈希表来记录在初始的集合中出现过的元素,然后我们枚举可能还可以在插入的数据 \(i\) (\(1\leq i \leq 5 \times 10^4\) ) ,在枚举过程中,如果已经在集合中就直接跳过,如果不在集合中,就需要开始判断,判断的过程中,遍历 在 $1 \leq x \leq 1 \times 10^5 $ 中 \(i\) 的倍数,这里注意,我考场上把每两个 \(i\) 的倍数都进行了 \(gcd\)运算, 这样直接导致我考场上这一题 \(TLE\) 了几十发...... 实际上,只需要把所有的 \(i\) 的倍数的数一起求最大公倍数,如果最大公倍数为 \(i\) 那么说明 \(i\) 最后需要被插入到集合 \(S\) 中.这里开始证明: 如果存在 \(k_1\cdot i\) 与 $ k_2 \cdot i$ 的最大公倍数为 \(i\) ,就可以得出 \(gcd(k_1,k_2)=1\) , \(k_1\) 和 \(k_2\) 互质,\(gcd (k_1,k_2 ,......k_{n-1} ,k_{n})=1\) ,那么 . 下证必要性, 若存在 $gcd (k_1 \cdot i,k_2 \cdot i,......k_{n-1} \cdot i,k_{n} \cdot i) = i $ ,即 \(gcd (k_1,k_2 ,......k_{n-1} ,k_{n})=1\) ,我们如何证明存在 \(gcd(k_i,k_j)=1\) 呢? 该出采用反证法,如果 任意 \(k_i\) 与 \(k_j\) 都两两不互质,则 存在 公因数 \(t\) ($ t != 1$)可以被提出来最后必然存在 \(gcd(k_1,k_2,k_3,......k_{n-1},k_n) != 1\) ,与结论相悖 ,故可以得出, 若所有的\(i\) 的倍数的元素的公因数是 \(i\) ,那么必然存在最少一对 \(i\) 的倍数的元素的公因数是 \(i\) ,若在 \(i\) 的倍数的元素中存在两个数的公因数是 \(i\) ,那么必然存在所有的 \(i\)的倍数的元素的公因数 \(\leq i\) ,也就是为 \(i\) ,所以综上只需要求一下所有的 \(i\) 的倍数的元素的最大公因数并判断是否为 \(i\) 即可得出是否存在两个元素的\(gcd(a_i,a_j)\)是否为 $ i $.
- 总结: 对基本的数论知识不熟。
AC code:
#include <bits/stdc++.h>
#define print(x) cout<<#x<<'='<<x<<'\n'
using namespace std;
const int maxn = 1e5 + 9;
int a[maxn];
int read()
{
int x = 0, f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -1;
c = getchar();
}
while (isdigit(c))
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int n;
int gcd(int x, int y)
{
return y == 0 ? x : gcd(y, x % y);
}
int ct=0;
void solve()
{
auto Y = [&]()
{
cout << "dXqwq" << "\n";
};
auto N = [&]()
{
cout << "Haitang" << '\n';
};
cin >> n;
vector<bool> mm(1e5 + 9, 0);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
mm[a[i]] = 1;
}
int count = 0;
for (int _ = 50000; _ >= 1; _--)
{
// print(_);
if (!mm[_])
{
int t=0;
for (int i = 2*_; i <= 100000; i+=_)
{
if (mm[i])
{
t=__gcd(t,i);
}
}
if(t==_)
{
mm[_]=1;
count++;
}
}
}
if(count&1)
{
Y();
}
else N();
// print(++ct);
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),cout.tie(0);
// freopen("1data.in","r",stdin);
int t;
// int st = clock();
cin >> t;
while (t--)
solve();
// int ed = clock();
// cerr << ed - st;
return 0;
}