[CCPC陝西省賽2022 H題] Cute Rabbit
題目描述
有 \(n\) 只白色的兔子,把其中 \(m\) 只染成綠色。每隻兔子上有一個數 \(a_i\) ,如果所有白色兔子上的數對所有綠色兔子上的數兩兩取餘的值均相同,則該種染色方式合法,求能夠使染色合法的最大的 \(m\) 。
輸入格式
第一行有一個整數 \(n(2 \leq n \leq 10^5)\) ,表示兔子的數量。
第二行有 \(n\) 個整數 \(a_1, a_2, ..., a_n (1 \leq a_i \leq 10^6)\)。
輸出格式
輸出一行一個整數,表示問題的答案。
題解
首先考慮到的一種情況是把除了最小的數都塗成綠色,此時所有白數對綠數取餘的答案都是其本身,顯然合法。
考慮其他的情況。不難得出,所有綠色的數必須小於白色的數。因此,我們將所有數排序,之後列舉白數和綠數的分界線即可。此時,問題轉化成了將前 \(i\) 個數染成綠色之後如何判斷該染色方案是否合法。透過觀察可以發現,染色合法的充分必要條件是 \(gcd(a_{i+1}, a_{i+2}, ..., a_n) \% lcm(a_1, a_2, ..., a_i) = 0\) 。因此,我們只需要預處理出字首 \(lcm\) 和字尾 \(gcd\)即可 \(O(1)\) 的判斷染色的合法性。
AC程式碼
//
// Created by wxy3265 on 2024/4/16.
//
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MAXN = 1e6 + 3;
int n;
int a[MAXN], l[MAXN], g[MAXN];
int gcd(int x, int y) {
return y? gcd(y, x % y): x;
}
inline int lcm(int x, int y) {
return x * y / gcd(x, y);
}
signed main() {
int ans = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
for (int i = 2; i <= n; i++) {
if (a[i] > a[1]) ans++;
}
if (ans == 0 || ans == n - 1) {
cout << n - 1;
return 0;
}
int tot = 1;
for (int i = 1; i <= n; i++) {
if (i == 1) l[i] = a[i];
else l[i] = lcm(l[i - 1], a[i]);
if (l[i] <= a[n]) tot++;
}
g[n - 1] = a[n] - a[n - 1];
for (int i = n - 2; i > 0; i--) {
g[i] = gcd(g[i + 1], a[i + 1] - a[i]);
}
g[n] = a[n];
if (a[n] % l[n] == 0) ans = n - 1;
for (int i = 1; i <= n - 1 && i <= tot - 1; i++) {
if (g[i + 1] % l[i] == 0) {
ans = max(ans, i);
}
}
cout << ans << '\n';
return 0;
}