Good Bye 2022: 2023 is NEAR
C. Koxia and Number Theory
判断一个长度为n的正整数数组是否存在一个大于0的数x使得任意 1 ≤ i < j ≤ n 1 \leq i \lt j \leq n 1≤i<j≤n
g c d ( a i + x , a j + x ) = 1 gcd(a_i + x, a_j + x) = 1 gcd(ai+x,aj+x)=1
数据范围: 2 ≤ n ≤ 100 , 1 ≤ a i ≤ 1 0 18 2 \leq n \leq 100, 1 \leq a_i \leq 10^{18} 2≤n≤100,1≤ai≤1018
- 如果 a i a_i ai不是两两不同的, 那么答案为false
- 对于一个质数P, 令 c n t j cnt_j cntj是 j j j在 [ a 1 m o d p , a 2 m o d p , . . . a n m o d p ] [a_1\quad mod\quad p, a_2\quad mod\quad p, ...a_n\quad mod\quad p] [a1modp,a2modp,...anmodp]中出现的次数,如果min( c n t 0 , c n t 1 , . . . , c n t p − 1 ≥ 2 cnt_0, cnt_1, ...,cnt_{p- 1}\geq2 cnt0,cnt1,...,cntp−1≥2), 则该情况为false
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <set>
using namespace std;
using ll = long long;
const int N = 110;
int n;
ll a[N];
int cnt[N];
void solve() {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
}
sort(a, a + n);
for(int i = 1; i < n; i++) {
if(a[i] == a[i - 1]) {
return puts("NO"), void();
}
}
for(int mod = 2; mod <= n / 2; mod ++) {
fill(cnt, cnt + mod, 0);
for(int i = 0; i < n; i++) {
cnt[a[i] % mod]++;
}
if(*min_element(cnt, cnt + mod) >= 2) {
return puts("NO"), void();
}
}
puts("YES");
}
int main() {
// freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while(t--) solve();
return 0;
}
D. Koxia and Game
- 只有每一轮 d i d_i di对于 M a h i r u Mahiru Mahiru都只有一种选择时, K o x i a Koxia Koxia才可能获胜
- 令P是一个长度为n的数组, 其中
P
i
P_i
Pi是
a
i
a_i
ai和
b
i
b_i
bi中的一者,
K
o
x
i
a
Koxia
Koxia获胜当且仅当p可能是一个排列
- 当P可能是一个排列时,令 c i c_i ci = p i p_i pi, 使得 M a h i r u Mahiru Mahiru在每一轮中都选择 d i = p i d_i = p_i di=pi, 所以 K o x i a Koxia Koxia获胜
- 当P不可能是一个排列时, 则不存在c使得 K o x i a Koxia Koxia获胜
- 需要一个算法判定P是否可能是一个排列
- 将 a i 和 b i a_i 和 b_i ai和bi连接一条无向边, 如果存在连通块的边和点的数量不同时,则无解,见样例二
- 每一个边等于点的连通分量可以当作一棵树加上一条附加边
- 附加边与其他树边形成环, 此时有两种边选点的方案
- 附加边形成自环,此时可选的方案为n
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
using ll = long long;
const int N = 1e5 + 10, MOD = 998244353;
int n;
int a[N], b[N], f[N], cntV[N], cntE[N], selfLoop[N];
void init() {
for(int i = 1; i <= n; i++) {
f[i] = -1;
cntV[i] = 1;
cntE[i] = 0;
selfLoop[i] = 0;
}
}
int find(int x) {
return f[x] < 0 ? x : f[x] = find(f[x]);
}
void merge(int x, int y) {
int fx = find(x), fy = find(y);
if(f[fx] < f[fy]) {
f[fx] += f[fy], f[fy] = fx;
cntV[fx] += cntV[fy];
cntE[fx] += cntE[fy];
selfLoop[fx] |= selfLoop[fy];
} else {
f[fy] += f[fx], f[fx] = fy;
cntV[fy] += cntV[fx];
cntE[fy] += cntE[fx];
selfLoop[fy] |= selfLoop[fx];
}
}
void solve() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
init();
for(int i = 1; i <= n; i++) {
if(find(a[i]) != find(b[i])) {
merge(a[i], b[i]);
}
cntE[find(a[i])]++;
if(a[i] == b[i]) selfLoop[find(a[i])] = 1;
}
ll res = 1ll;
for(int i = 1; i <= n; i++) {
if(f[i] < 0) {
if(cntV[find(i)] != cntE[find(i)]) {
return puts("0"), void();
}
res = res * (selfLoop[find(i)] ? n : 2) % MOD;
}
}
printf("%lld\n", res);
}
int main() {
// freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while(t--) solve();
return 0;
}