Codeforces Round 985 div1+2 個人題解(A~E)
Dashboard - Refact.ai Match 1 (Codeforces Round 985) - Codeforces
火車頭
#include <bits/stdc++.h>
using namespace std;
#define ft first
#define sd second
#define yes cout << "yes\n"
#define no cout << "no\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define all1(x) x.begin() + 1, x.end()
#define unq_all(x) x.erase(unique(all(x)), x.end())
#define unq_all1(x) x.erase(unique(all1(x)), x.end())
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL
#define RED cout << "\033[91m" // 紅色
#define GREEN cout << "\033[92m" // 綠色
#define YELLOW cout << "\033[93m" // 藍色
#define BLUE cout << "\033[94m" // 品紅
#define MAGENTA cout << "\033[95m" // 青色
#define CYAN cout << "\033[96m" // 青色
#define RESET cout << "\033[0m" // 重置
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// typedef __int128_t i128;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<string, ll> psl;
typedef tuple<int, int, int> ti3;
typedef tuple<ll, ll, ll> tl3;
typedef tuple<ld, ld, ld> tld3;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<vi> vvi;
typedef vector<vl> vvl;
// std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
template <typename T>
inline T read()
{
T x = 0;
int y = 1;
char ch = getchar();
while (ch > '9' || ch < '0')
{
if (ch == '-')
y = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return x * y;
}
template <typename T>
inline void write(T x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x >= 10)
{
write(x / 10);
}
putchar(x % 10 + '0');
}
/*#####################################BEGIN#####################################*/
void solve()
{
}
int main()
{
ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
// freopen("test.in", "r", stdin);
// freopen("test.out", "w", stdout);
int _ = 1;
std::cin >> _;
while (_--)
{
solve();
}
return 0;
}
/*######################################END######################################*/
// 連結:
A. Set
給你一個正整數 \(k\) 和一個由 \(l\) 至 \(r\) (含)的所有整陣列成的集合 \(S\)。
您可以執行以下兩步運算的任意次數(可能為零):
首先,從集合 \(S\) 中選擇一個數字 \(x\),使得 \(S\) 中至少有 \(k\) 個 \(x\) 的倍數(包括 \(x\) 本身);
然後,從 \(S\) 中刪除 \(x\) (注意沒有刪除任何其他內容)。
求可以進行的最大運算元。
輸入
每個測試包含多個測試用例。輸入的第一行包含一個整數 \(t\) (\(1 \leq t \leq 10^4\))—— 測試用例的數量。測試用例說明如下。
每個測試用例的唯一一行包含三個整數 \(l\)、\(r\) 和 \(k\) (\(1 \leq l \leq r \leq 10^9\),\(1 \leq k \leq r - l + 1\))—— 最小整數 \(S\)、最大整數 \(S\) 和引數 \(k\)。
輸出
對於每個測試用例,輸出一個整數——可執行的最大運算元。
示例
輸入
8
3 9 2
4 9 1
7 9 2
2 10 2
154 220 2
147 294 2
998 24435 3
1 1000000000 2
輸出
2
6
0
4
0
1
7148
500000000
提示
在第一個測試用例中,初始時 \(S=\{3,4,5,6,7,8,9\}\)。一個可能的最佳操作序列是:
選擇 \(x=4\) 進行第一次操作,因為 \(S\) 中有兩個 \(4\) 的倍數:\(4\) 和 \(8\)。\(S\) 變為 \(\{3,5,6,7,8,9\}\);
選擇 \(x=3\) 進行第二次操作,因為 \(S\) 中有三個 \(3\) 的倍數:\(3\)、\(6\) 和 \(9\)。\(S\) 變為 \(\{5,6,7,8,9\}\)。
在第二個測試用例中,初始時 \(S=\{4,5,6,7,8,9\}\)。一個可能的最佳操作序列是:
選擇 \(x=5\),\(S\) 變為 \(\{4,6,7,8,9\}\);
選擇 \(x=6\),\(S\) 變為 \(\{4,7,8,9\}\);
選擇 \(x=4\),\(S\) 變為 \(\{7,8,9\}\);
選擇 \(x=8\),\(S\) 變為 \(\{7,9\}\);
選擇 \(x=7\),\(S\) 變為 \(\{9\}\);
選擇 \(x=9\),\(S\) 變為空集。
在第三個測試用例中,初始時 \(S=\{7,8,9\}\)。對於 \(S\) 中的每個 \(x\),無法找到除 \(x\) 本身以外的其他 \(x\) 的倍數。由於 \(k=2\),您無法進行任何操作。
在第四個測試用例中,初始時 \(S=\{2,3,4,5,6,7,8,9,10\}\)。一個可能的最佳操作序列是:
選擇 \(x=2\),\(S\) 變為 \(\{3,4,5,6,7,8,9,10\}\);
選擇 \(x=4\),\(S\) 變為 \(\{3,5,6,7,8,9,10\}\);
選擇 \(x=3\),\(S\) 變為 \(\{5,6,7,8,9,10\}\);
選擇 \(x=5\),\(S\) 變為 \(\{6,7,8,9,10\}\)。
解題思路
對於一個數\(n\),我們能構造出的最大的有 \(k\) 個 \(x\) 的倍數的\(x\)為\(\lfloor \frac{n}{k}\rfloor\)。因此,答案為\(\max(0,\lfloor \frac{r}{k}\rfloor-l+1)\)
實現程式碼
void solve()
{
ll l, r, k;
cin >> l >> r >> k;
cout << max(0ll, r / k - l + 1) << "\n";
}
B. Replacement
您有一個長度為 \(n\) 的二進位制字串 \(s\),而艾瑞絲會給出另一個長度為 \(n-1\) 的二進位制字串 \(r\)。
艾瑞絲將和你玩一個遊戲。在遊戲過程中,你將對 \(s\) 執行 \(n-1\) 操作。在第 \(i\) 次操作中(\(1 \leq i \leq n-1\)):
首先,你要選擇一個索引 \(k\),使得 \(1 \leq k \leq |s| - 1\) 且 \(s_k \neq s_{k+1}\)。如果無法選擇這樣的索引,那麼就輸了;
然後,將 \(s_k s_{k+1}\) 替換為 \(r_i\)。請注意,這會使 \(s\) 的長度減少 \(1\)。
如果所有的 \(n-1\) 操作都成功執行,那麼你就贏了。
請判斷你是否有可能贏得這個遊戲。
輸入
每個測試包含多個測試用例。輸入的第一行包含一個整數 \(t\) (\(1 \leq t \leq 10^4\))—— 測試用例的數量。測試用例說明如下。
每個測試用例的第一行包含一個整數 \(n\) (\(2 \leq n \leq 10^5\))—— \(s\) 的長度。
第二行包含長度為 \(n\) (\(s_i = 0\) 或 \(1\))的二進位制字串 \(s\)。
第三行包含長度為 \(n-1\) (\(r_i = 0\) 或 \(1\))的二進位制字串 \(r\)。
保證所有測試用例中 \(n\) 的總和不超過 \(10^5\)。
輸出
對於每個測試用例,如果能贏得遊戲,則列印 "YES"(不帶引號),否則列印 "NO"(不帶引號)。
您可以用任何大小寫(大寫或小寫)輸出答案。例如,字串 "yEs"、"yes"、"Yes" 和 "YES" 將被識別為肯定回答。
示例
輸入
6
2
11
0
2
01
1
4
1101
001
6
111110
10000
6
010010
11010
8
10010010
0010010
輸出
NO
YES
YES
NO
YES
NO
提示
在第一個測試用例中,您無法執行第一次操作。因此,您輸了遊戲。
在第二個測試用例中,您可以選擇 \(k=1\) 進行唯一的操作,之後 \(s\) 變為 \(1\)。因此,您贏得了遊戲。
在第三個測試用例中,您可以執行以下操作:\(110 \to r_1 = 0101 \to r_2 = 010 \to r_3 = 11\)。
解題思路
注意到我們每次是選擇一個\(01\)或者\(10\)來進行替換,使其留下\(1\)或者\(0\),因此,每個替換都等價於刪除另一種數字,例如替換為\(1\)等價於刪除一個\(0\),所以,我們可以維護\(0\)和\(1\)的數量,如果在最後一次刪除前\(0\)和\(1\)的數量歸零則遊戲輸了。
實現程式碼
void solve()
{
int n;
string s, r;
cin >> n >> s >> r;
int cnt0 = 0;
int cnt1 = 0;
for (auto c : s)
{
if (c == '1')
cnt1++;
else
cnt0++;
}
if (cnt0 == 0 || cnt1 == 0)
{
NO;
return;
}
for (int i = 0; i < n - 1; i++)
{
if (r[i] == '1')
cnt0--;
else
cnt1--;
if (i == n - 2)
continue;
if (cnt0 == 0 || cnt1 == 0)
{
NO;
return;
}
}
YES;
}
C. New Rating
你好,Codeforcescode!
凱文曾經是 Codeforces 的參與者。最近,KDOI 團隊開發了一個名為 Forcescode 的新線上裁判。
凱文參加過 Forcescode 上的 \(n\) 場比賽。在第 \(i\) 場比賽中,他的表現評分為 \(a_i\)。
現在他黑進了 Forcescode 的後臺,將選擇一個時間間隔 \([l,r]\) (\(1 \leq l \leq r \leq n\)),然後跳過這個時間間隔內的所有比賽。之後,他的評分將按以下方式重新計算:
最初,他的評分為 \(x=0\);
每次 \(1 \leq i \leq n\),在第 \(i\) 場比賽之後:
如果 \(l \leq i \leq r\),則跳過這場比賽,等級分保持不變;
否則,他的評級將根據以下規則更新:
如果 \(a_i > x\),他的評分 \(x\) 將增加 \(1\);
如果 \(a_i = x\),他的評分 \(x\) 將保持不變;
如果 \(a_i < x\),他的評分 \(x\) 將減少 \(1\)。
如果凱文以最佳方式選擇了區間 \([l,r]\),您必須幫助他找到重新計算後的最大可能評分。注意凱文至少要跳過一次比賽。
輸入
每個測試包含多個測試用例。輸入的第一行包含一個整數 \(t\) (\(1 \leq t \leq 5 \cdot 10^4\))—— 測試用例的數量。測試用例說明如下。
每個測試用例的第一行包含一個整數 \(n\) (\(1 \leq n \leq 3 \cdot 10^5\))—— 競賽次數。
第二行包含 \(n\) 個整數 \(a_1, a_2, \ldots, a_n\) (\(1 \leq a_i \leq n\))—— 競賽中的效能評級。
保證所有測試用例中 \(n\) 的總和不超過 \(3 \cdot 10^5\)。
輸出
對於每個測試用例,輸出一個整數——如果凱文以最佳方式選擇間隔,重新計算後可能的最大評級。
示例
輸入
5
6
1 2 3 4 5 6
7
1 2 1 1 1 3 4
1
1
9
9 9 8 2 4 4 3 5 3
10
1 2 3 4 1 3 2 1 1 10
輸出
5
4
0
4
5
提示
在第一個測試用例中,凱文必須跳過至少一場比賽。如果他選擇任何長度為 \(1\) 的區間,他的評分在重新計算後將等於 \(5\)。
在第二個測試用例中,凱文的最佳選擇是選擇區間 \([3,5]\)。在重新計算期間,他的評分變化如下:
\(0 \to a_1=1 \to a_2=2 \to \text{跳過}2 \to \text{跳過}2 \to \text{跳過}2 \to a_6=3 \to a_7=4\)。
在第三個測試用例中,凱文必須跳過唯一的比賽,因此他的評分將保持在初始值 \(0\)。
在第四個測試用例中,凱文的最佳選擇是選擇區間 \([7,9]\)。在重新計算期間,他的評分變化如下:
\(0 \to a_1=9 \to a_2=9 \to a_3=8 \to a_4=2 \to a_5=4 \to a_6=4 \to \text{跳過}4 \to \text{跳過}4 \to \text{跳過}4\)。
在第五個測試用例中,凱文的最佳選擇是選擇區間 \([5,9]\)。
解題思路
我們可以設計三個\(dp\)值\(f,g,h\),\(f[i]\)代表第\(i\)次比賽不進行任何跳過的評分,\(g[i]\)代表第\(i\)次比賽正在進行跳過的最大評分,\(h[i]\)代表第\(i\)次比賽已經進行跳過後的最大平方,我們令\(calc(a[i])\)代表評級的更新規則,則可以得到以下狀態轉移方程:\(f[i]=f[i-1]+clac(a[i]),g[i]=\max(g[i-1],f[i]),h[i]=\max(h[i-1]+calc(a[i]),g[i-1])\)
實現程式碼
void solve()
{
int n;
cin >> n;
vi a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
vi f(n + 1, -inf);
vi g(n + 1, -inf);
vi h(n + 1, -inf);
f[0] = g[0] = h[0] = f[1] = h[1] = 0;
for (int i = 1; i <= n; i++)
{
int v = a[i];
if (f[i - 1] < v)
f[i] = f[i - 1] + 1;
else if (f[i - 1] == v)
f[i] = f[i - 1];
else
f[i] = f[i - 1] - 1;
g[i] = max(f[i], g[i - 1]);
if (i == 1)
continue;
if (h[i - 1] < v)
h[i] = h[i - 1] + 1;
else if (h[i - 1] == v)
h[i] = h[i - 1];
else
h[i] = h[i - 1] - 1;
h[i] = max(h[i], g[i - 1]);
}
cout << h[n] << endl;
}
D. Cool Graph
給你一個無向圖,其中有 \(n\) 個頂點和 \(m\) 條邊。
您最多可以執行以下操作 \(2 \cdot \max(n,m)\) 次:
選擇三個不同的頂點 \(a\)、\(b\) 和 \(c\),然後對每條邊 \((a,b)\)、\((b,c)\) 和 \((c,a)\) 執行以下操作:
如果該邊不存在,則新增該邊。相反,如果存在,則刪除。
當且僅當以下條件之一成立時,圖才被稱為酷圖:
該圖沒有邊,或
該圖是一棵樹。
您必須透過執行上述操作使圖形冷卻。請注意,您最多可以進行 \(2 \cdot \max(n,m)\) 次操作。
可以證明,總是存在至少一個解。
輸入
每個測試包含多個測試用例。第一行輸入包含一個整數 \(t\) (\(1 \leq t \leq 10^4\))—— 測試用例的數量。測試用例說明如下。
每個測試用例的第一行包含兩個整數 \(n\) 和 \(m\) (\(3 \leq n \leq 10^5\),\(0 \leq m \leq \min\left(\frac{n(n-1)}{2}, 2 \cdot 10^5\right)\))—— 頂點數和邊數。
接著是 \(m\) 行,\(i\) 行包含兩個整數 \(u_i\) 和 \(v_i\) (\(1 \leq u_i, v_i \leq n\))—— 第 \(i\) 條邊所連線的兩個節點。
保證所有測試用例中 \(n\) 的總和不超過 \(10^5\),所有測試用例中 \(m\) 的總和不超過 \(2 \cdot 10^5\)。
保證給定圖中不存在自迴圈或多重邊。
輸出
對於每個測試用例,在第一行輸出一個整數 \(k\) (\(0 \leq k \leq 2 \cdot \max(n,m)\))—— 運算次數。
然後輸出 \(k\) 行,第 \(i\) 行包含三個不同的整數 \(a\)、\(b\) 和 \(c\) (\(1 \leq a,b,c \leq n\))—— 你在第 \(i\) 次操作中選擇的三個整數。
如果有多個解,可以輸出其中任意一個。
示例
輸入
5
3 0
3 1
1 2
3 2
1 2
2 3
3 3
1 2
2 3
3 1
6 6
1 2
1 6
4 5
3 4
4 6
3 6
輸出
0
1
1 2 3
0
1
1 2 3
3
1 3 6
2 4 5
3 4 6
提示
在第一個測試用例中,圖已經是酷圖,因為沒有邊。
在第二個測試用例中,執行唯一的操作後,圖變成了一棵樹,因此是酷圖。
在第三個測試用例中,圖已經是酷圖,因為它是一棵樹。
在第四個測試用例中,執行唯一的操作後,圖沒有邊,因此是酷圖。
解題思路
看到限制條件為最多可以進行 \(2 \cdot \max(n,m)\) 次操作,結合樹的邊數為 \(n-1\) ,因此我們可以考慮先將圖刪掉儘可能能多的邊,然後再重新構建出一棵樹,剛好可以接近用完操作。
順著這個思路往下想,對於一個度數大於等於 \(2\) 的點 \(x\) ,我們可以選擇對 \(x\) 和它的兩個鄰接點 \(y\) 和 \(z\) 進行操作,如果 \(y\) 和 \(z\) 存在一條邊,則一次性刪除了三條邊,否則,我們刪除了兩條邊並構建了一條邊 \((y,z)\) ,至少刪除了一條邊。因此,我們最多不會超過 \(m\) 次,就可以將 這個圖刪的只剩下孤點和孤邊。如果沒有孤邊,說明所有邊已被刪除,直接滿足要求。
考慮對一堆孤點和孤邊進行操作來構建一棵樹。
我們可以選取一個孤邊作為樹的基礎。
如果遇見孤點,則對樹的兩個端點 \(x\) 和 \(y\) 以及孤點 \(z\) 進行操作,這樣我們相當於在 \(x\) 和 \(y\) 之間插入了一個點 \(z\) 使得邊 \(x\rarr y\) 變成 \(x \rarr z \rarr y\) ,然後我們把 \(z\) 賦值給 \(y\) 即可。
如果遇見孤邊,則對孤邊的兩個端點 \(u\) 和 \(v\) 和樹的端點 \(x\) 進行操作,這樣我們相當於將 \(u\) 和 \(v\) 與端點 \(x\) 建邊,使得邊 \(u \rarr v ,x\) 變成 \(u \rarr x \larr v\) 。
實現程式碼
void solve()
{
int n, m;
cin >> n >> m;
vector<set<int>> adj(n + 1);
for (int i = 0; i < m; i++)
{
int u, v;
cin >> u >> v;
adj[u].insert(v);
adj[v].insert(u);
}
if (m == 0)
{
cout << "0\n";
return;
}
vector<array<int, 3>> ans;
auto del = [&](int a, int b, int c)
{
adj[a].erase(b);
adj[b].erase(a);
adj[a].erase(c);
adj[c].erase(a);
if (adj[b].find(c) != adj[b].end())
{
adj[b].erase(c);
adj[c].erase(b);
}
else
{
adj[b].insert(c);
adj[c].insert(b);
}
};
for (int i = 1; i <= n; i++)
{
while (adj[i].size() >= 2)
{
int a = i;
int b = *adj[i].begin();
int c = *next(adj[i].begin());
ans.pb({a, b, c});
del(a, b, c);
}
}
int u = 0, v = 0;
for (int i = 1; i <= n; i++)
{
if (adj[i].size() == 1)
{
u = i;
v = *adj[i].begin();
break;
}
}
if (u)
{
vb vis(n + 1);
vis[u] = vis[v] = 1;
for (int i = 1; i <= n; i++)
{
if (vis[i])
continue;
if (adj[i].size() == 1)
{
ans.pb({u, i, *adj[i].begin()});
vis[i] = 1;
vis[*adj[i].begin()] = 1;
}
else
{
ans.pb({u, v, i});
vis[i] = 1;
v = i;
}
}
}
cout << ans.size() << "\n";
for (auto [a, b, c] : ans)
{
cout << a << " " << b << " " << c << "\n";
}
}
E. Common Generator
對於兩個整數 \(x\) 和 \(y\) (\(x,y \geq 2\)),當且僅當 \(x\) 可以透過執行下面的操作轉換為 \(y\) 時,我們才會說 \(x\) 是 \(y\) 的生成器:
選擇 \(x\) 的除數 \(d\) (\(d \geq 2\)),然後將 \(x\) 增加 \(d\)。
例如:
\(3\) 是 \(8\) 的生成器,因為我們可以進行以下運算:\(3 \xrightarrow{d=3} 6 \xrightarrow{d=2} 8\);
\(4\) 是 \(10\) 的生成器,因為我們可以進行以下運算:\(4 \xrightarrow{d=4} 8 \xrightarrow{d=2} 10\);
\(5\) 不是 \(6\) 的生成器,因為我們無法透過上述操作將 \(5\) 轉化為 \(6\)。
現在,凱文給你一個陣列 \(a\),由 \(n\) 個成對不同的整數 (\(a_i \geq 2\)) 組成。
你必須找到一個整數 \(x \geq 2\),使得每個 \(1 \leq i \leq n\) 的生成數 \(x\) 都是 \(a_i\) 的生成數,或者確定這樣的整數不存在。
輸入
每個測試包含多個測試用例。輸入的第一行包含一個整數 \(t\) (\(1 \leq t \leq 10^4\))—— 測試用例的數量。測試用例說明如下。
每個測試用例的第一行都包含一個整數 \(n\) (\(1 \leq n \leq 10^5\))—— 陣列 \(a\) 的長度。
第二行包含 \(n\) 個整數 \(a_1, a_2, \ldots, a_n\) (\(2 \leq a_i \leq 4 \cdot 10^5\))—— 陣列 \(a\) 中的元素。可以保證這些元素是成對不同的。
保證所有測試用例中 \(n\) 的總和不超過 \(10^5\)。
輸出
對於每個測試用例,輸出一個整數 \(x\)—— 您找到的整數。如果不存在有效的 \(x\),則列印 \(-1\)。
如果有多個答案,可以輸出任意一個。
示例
輸入
4
3
8 9 10
4
2 3 4 5
2
147 154
5
3 6 8 25 100000
輸出
2
-1
7
3
提示
在第一個測試用例中,對於 \(x=2\):
\(2\) 是 \(8\) 的生成器,因為我們可以進行以下運算:\(2 \xrightarrow{d=2} 4 \xrightarrow{d=4} 8\);
\(2\) 是 \(9\) 的生成器,因為我們可以進行以下運算:\(2 \xrightarrow{d=2} 4 \xrightarrow{d=2} 6 \xrightarrow{d=3} 9\);
\(2\) 是 \(10\) 的生成器,因為我們可以進行以下運算:\(2 \xrightarrow{d=2} 4 \xrightarrow{d=2} 6 \xrightarrow{d=4} 10\)。
在第二個測試用例中,可以證明不可能找到四個整數的公共生成器。
解題思路
由於一個數 \(x\) 可以增加它的因數 \(d\) ,我們很容易就可以想到,要構造一個數 \(a_i\) ,我們只要要構造出它的因數的倍數 \(kd\) 並使得 \(kd \le a_i\),我們就可以很輕鬆的構造出 \(a_i\) 。由於每次操作都是對當前值進行加法,因此我們因數 \(d\) 選的越小,我們的操作空間越大,所以為了構造出 \(a_i\) ,我們一定是選擇它的最小質因數 \(p\) 來進行構造。
- 考慮 \(a_i\) 為偶數,我們只要選擇 \(x=2\),就一定可以構造出 \(a_i\) 。
- 考慮 \(a_i\) 為非質數的奇數,我們也只要選擇 \(x=2\),就一定可以構造出 \(a_i\) 。對於\(a_i\),我們只需要將 \(x\) 加上 \(p-1\) 次 \(2\) 就可以獲得因數最小包含 \(a_i\) 最小質數因子 \(p\) 的數 \(2\times p\) 。由於\(a_i\) 為非質數的奇數,其最小質因子最小為 \(3\) ,因此 $a_i \gt 2\times p $,我們只要對 \(2 \times p\) 不斷加上 \(p\) 就可以得到 \(a_i\) 。
- 考慮 \(a_i\) 為質數,我們只能選擇它自己來獲得它。
綜上
-
如果 \(a\) 中質數數量大於 \(1\) ,則不存在符合要求的整數。
-
如果 \(a\) 中質數數量等於 \(0\) ,則選擇 \(x=2\) 一定可以構造出所有 \(a_i\) 。
-
如果 \(a\) 中質數數量等於 \(1\) ,則我們只能選擇選擇 \(x=\text{pri}\) ,\(\text{pri}\) 為唯一的質數。
考慮檢查\(x=\text{pri}\) 是否可以生成所有 \(a_i\)
- 對於 \(a_i\) 為偶數,只要 \(a_i \le 2\times \text{pri}\) ,我們就可以使得選擇器包含因數 \(2\) 從而構造出所有偶數。
- 對於 \(a_i\) 為奇數,只要\(a_i - p \le 2\times \text{pri}\) ,我們就可以使得選擇器包含因數 \(2\) 從而構造出 \(2 \times p\) 進而構造出 \(a_i\) 。
實現程式碼
const int N = 4e5;
vector<int> minp; // 儲存每個數的最小質因子
vector<int> primes; // 儲存找到的所有質數
// 尤拉篩函式
void sieve(int n)
{
minp.assign(n + 1, 0); // 初始化最小質因子陣列
primes.clear(); // 清空質數陣列
for (int i = 2; i <= n; i++)
{
if (minp[i] == 0)
{ // 如果 minp[i] 仍為 0,說明 i 是質數
minp[i] = i; // 記錄 i 的最小質因子為自身
primes.push_back(i); // 將 i 新增到質數列表中
}
// 遍歷已找到的質數
for (auto p : primes)
{
if (i * p > n)
{ // 如果 i * p 超過 n,停止
break;
}
minp[i * p] = p; // 記錄 i * p 的最小質因子
if (p == minp[i])
{ // 如果當前質數等於 i 的最小質因子,停止
break;
}
}
}
}
void solve()
{
int n;
cin >> n;
vi a(n);
int cntPri = 0;
int pri = 0;
for (int i = 0; i < n; i++)
{
cin >> a[i];
if (minp[a[i]] == a[i])
{
cntPri++;
pri = a[i];
}
}
if (cntPri >= 2)
{
cout << "-1\n";
return;
}
if (cntPri == 0)
{
cout << "2\n";
return;
}
for (int i = 0; i < n; i++)
{
if (a[i] == pri)
continue;
int v = a[i] & 1 ? a[i] - minp[a[i]] : a[i];
if (pri * 2 > v)
{
cout << "-1\n";
return;
}
}
cout << pri << "\n";
}
這場沒打,第二天就是區賽,不敢打。
感覺這場挺簡單的。