人生巔峰,這是我第一次 \(\textrm{AK div2}\)!
一場 \(\textrm{div2}\) 讓我信心大增,感謝中國同胞!!!
Link \(\textrm{to Codeforces}\)。
Contest
A. Subset Mex
Legend
給定長度為 \(n\ (1 \le n \le 100)\) 的數組 \(a\ (0 \le a_i \le 100)\),把它們分成兩個集合,使得 \(\operatorname{mex}(S_1)+\operatorname{mex}(S_2)\) 盡量大,可以為空。
數據組數 \(1 \le t \le 100\)。
Editorial
顯然貪心構造即可。
Code
可以但沒必要。
B. Maximum Product
Legend
給定長度為 \(n\ (5 \le n,\sum n \le 10^5)\) 的數組 \(a\ ( |a_i| \le 3 \times 10^3)\)。從中選 \(5\) 個數字,使得乘積盡可能大。
數據組數 \(1 \le t \le 2\cdot10^4\)。
Editorial
顯然排完序只能選兩端的。
Code
可以但沒必要。
C. Link Cut Centroids
Legend
給定一棵樹,共 \(n\ (3 \le n,\sum n \le 10^5)\) 個節點,請刪除一條邊再加上一條邊,使得圖依然聯通且樹的重心有且僅有一個。
數據組數 \(1 \le t \le 10^4\)。
Editorial
找到重心。
- 如果只有一個,隨便斷一條邊再連上。
- 如果有兩個,則它們肯定不是葉子,那么把其中的一個重心任選一個子樹接到另一個重心去即可。
Code
int c1 ,c2 ,sz[MX] ,mx[MX] ,n;
void dfs(int x ,int f){
mx[x] = 0;
sz[x] = 1;
for(int i = head[x] ,d ; i ; i = h[i].next){
if((d = h[i].node) == f) continue;
dfs(d ,x);
sz[x] += sz[d];
mx[x] = max(mx[x] ,sz[d]);
}
mx[x] = max(mx[x] ,n - sz[x]);
if(mx[x] == mx[c1]) c2 = x;
if(mx[x] < mx[c1]){
c1 = x;
c2 = 0;
}
}
void solve(){
mx[0] = 114514;
cin >> n;
for(int i = 1 ; i <= n ; ++i) head[i] = 0;
tot = c2 = c1 = 0;
int u ,v;
for(int i = 1 ; i < n ; ++i){
cin >> u >> v;
addedge(u ,v);
}
dfs(1 ,0);
if(!c2){
cout << u << " " << v << endl;
cout << u << " " << v << endl;
}
else{
for(int i = head[c1] ,d ; i ; i = h[i].next){
if((d = h[i].node) != c2){
cout << c1 << " " << d << endl;
cout << d << " " << c2 << endl;
break;
}
}
}
}
D. Three Sequences
Legend
給定長度為 \(n\ (1 \le n \le 10^5)\) 的數組 \(a\ (|a_i| \le 10^9)\)。
同時有另外兩個長度與 \(a\) 相同的數組 \(b,c\) 滿足:
- \(b_i+c_i=a_i\)。
- \(b\) 單調不降。
- \(c\) 單調不升。
你需要最小化 \(\max(b_i,c_i)\),輸出這個結果。
以及還有 \(q\ (1 \le q \le 10^5)\) 次修改,將 \(a\) 區間 \([l,r]\) 加上 \(x\ (|x| \le 10^9)\)。
Editorial
好題!有那么點意思。
因為 \(b\) 單調不降,我們考慮如下式子:
\(b_2=b_1+ \Delta_1\ (\Delta \ge 0)\),\(b_1+c_1=a_1\),\(b_2+c_2=a_2\),\(c_1 \ge c_2\)。
整理可得:\(a_1+\Delta_1 \ge a_2\)。
我們肯定是希望 \(\sum \Delta\) 盡可能小,所以 \(\Delta\) 取到等號最優,即 \(\Delta_i=\max(0,a_{i+1}-a_i)\)。
我們要求的答案是 \(\max(b_n,c_1)\),那我們得先把這個式子表示出來。
根據定義我們可以得到 \(b_n = b_1 + \sum \Delta\)。我們肯定是希望 \(c_1,b_n\) 比較接近,這樣才取到最優。
\(c_1=b_1+\sum \Delta\),整理得到 \(c_1 = \left\lceil \dfrac{a_1 + \sum \Delta}{2} \right\rceil\) 即為最終答案。
區間加只會改動差分數組的兩個位置,改變了 \(\Delta\) 的值。
Code
LL a[MX] ,del[MX] ,cost ,n;
void upd(int pos ,int v){
if(pos > n || pos == 1) return;
LL before = max(del[pos] ,0LL);
del[pos] += v;
cost += max(del[pos] ,0LL) - before;
}
LL Ans(LL x){
if(x >= 0) return (x + 1) / 2;
return x / 2;
}
void solve(){
cost = 0;
cin >> n;
for(int i = 1 ; i <= n ; ++i){
cin >> a[i];
del[i] = a[i] - a[i - 1];
if(i != 1 && del[i] >= 0) cost += del[i];
}
cout << Ans(a[1] + cost) << endl;
int q; cin >> q;
for(int i = 1 ; i <= q ; ++i){
int l ,r ,d; cin >> l >> r >> d;
if(l == 1) a[1] += d;
else{
upd(l ,d);
}
if(r != n){
upd(r + 1 ,-d);
}
cout << Ans(a[1] + cost) << endl;
}
}
E. Deleting Numbers
Legend
本題為交互題。
你有一個集合 \(\{1,2,\cdots,n\}\ (1 \le n \le 10^5)\),現在有一個數 \(x\ (1 \le x \le n)\),你要猜它。你可以對集合進行如下操作:
- 詢問集合中有多少個 \(a\ (1 \le a \le n)\) 的倍數。
- 詢問集合中有多少個 \(a\ (1 \le a \le n)\) 的倍數,並把 \(a\) 的倍數刪除。特別地,\(x\) 永遠不會被刪除。
- 告訴交互器答案是 \(a\)。這個操作只能執行一次。
你最多可以操作 \(10^4\) 次。
Editorial
a useful web
這種題目嘛,所有人都會想到質數。於是我馬上進了 \(\textrm{number empire}\) 網站(Link),搜索了 \(10^5\) 以內的質數個數,發現很巧,正好有 \(9592\) 個,與題目限制的 \(10^4\) 十分接近。發現到答案有可能是個大質數,因為每一個質數都至少要做一次操作 \(2\),所以詢問次數的下界就是 \(9592\)。我們還有 \(408\) 次可以做其他的事情。
a well-known conclusion
用到一個十分基礎的結論:\(> \sqrt{n}\) 的質因子最多只有一個。
for prime \(\le \sqrt{n}\)
我馬上發現 \(\sqrt{n}=316.227766\cdots\),發現 \(\le \sqrt{n}\) 的質數只有 \(65\) 個。我們不妨對這 \(65\) 個質數進行暴力操作,每次先刪了 \(p\) 的倍數,再詢問 $p1,p2,p^3\cdots $ 是否還有。發現這最多只需要 \(65+15\) 次就能搞定。(\(15\) 是因為 \(2^{17}>10^5\))。
for prime \(> \sqrt{n}\)
接下來對於 \(> \sqrt{n}\) 的質數還有 \(9528\) 個,但是這當中最多只有一個因子。我分了以下兩種情況討論:
- 這個數存在 \(\le \sqrt{n}\) 的因子。
那么可以對每一個 \(> \sqrt{n}\) 的質數使用操作 \(1\),看元素數量對不對,沒對上就說明肯定這個 \(>\sqrt{n}\) 的因子就是當前詢問的。
- 這個數不存在 \(< \sqrt{n}\) 的因子。
考慮每 \(\sqrt{9528}=97.611474\cdots\) 個質數分成一塊,每刪除完一個塊中所有數就檢查一下 \(1\) 的倍數有多少個(即集合元素數量),如果沒對上就說明這個因子一定在這個塊里面。暴力檢查塊內元素即可。最多消耗 \(98+98=196\) 次。
所以最壞情況消耗次數是 \(9592+65+15+98+98=9868\) 次,可以通過。
復雜度我不太會算,如果是枚舉 \(1 \to n\),那復雜度是 \(O(n \log n)\) 但只枚舉了質數,遠遠達不到。
**upd: ** 復雜度與埃氏篩是一樣的,即 \(O(n \log \log n)\)。
Code
交互題調試還要自己寫交互器……
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MX = 1e5 + 233;
int pri[MX] ,Npri[MX] ,n ,tot;
int vis[MX];
int shouldrem;
void sieve(){
Npri[0] = Npri[1] = true;
for(int i = 2 ; i <= n ; ++i){
if(!Npri[i]) pri[++tot] = i ;
for(int j = 1 ; j <= tot && pri[j] * i <= n ; ++j){
int aim = pri[j] * i;
Npri[aim] = 1;
if(i % pri[j] == 0) break;
}
}
}
/*
int dele[MX] ,Ans;
int del(int x ,int v = 1){
int ret = 0;
for(int i = x ; i <= n ; i += x){
ret += !dele[i];
if(v == 0) continue;
if(i != Ans) dele[i] = 1;
}return ret;
}
*/
int AskB(int x){
cout << "B " << x << endl;
// return del(x);
cin >> x; return x;
}
int AskA(int x){
cout << "A " << x << endl;
// return del(x ,0);
cin >> x; return x;
}
int gar;
int main(){
cin >> n;
// Ans = 1949;
shouldrem = n;
sieve();
int Ans = 1;
int i = 1;
for( ; i <= tot && pri[i] <= min(317 ,n) ; ++i){
int p = pri[i];
gar = AskB(p);
for(int j = p ; j <= n ; j += p)
shouldrem -= !vis[j] ,vis[j] = 1;
int ok = AskA(p);
if(ok) Ans *= pri[i];
for(p *= pri[i] ; ok && p <= n ; p *= pri[i]){
ok = AskA(p);
if(ok) Ans *= pri[i];
}
}
if(Ans != 1){
for( ; i <= tot ; ++i){
gar = AskB(pri[i]);
int tmp = 0;
for(int j = pri[i] ; j <= n ; j += pri[i])
shouldrem -= !vis[j] ,tmp += !vis[j] ,vis[j] = 1;
if(gar != tmp){
Ans *= pri[i];
break;
}
}
}
else{
int cnt = 0;
for( ; i <= tot ; ++i){
++cnt;
AskB(pri[i]);
for(int j = pri[i] ; j <= n ; j += pri[i])
shouldrem -= !vis[j] ,vis[j] = 1;
if(cnt == 98 || i == tot){
gar = AskA(1);
if(gar != shouldrem){
for(int j = 0 ; j < 98 ; ++j){
gar = AskA(pri[i - j]);
if(gar){
Ans *= pri[i - j];
goto out;
}
}
}
cnt = 0;
}
}
}
out:
cout << "C " << Ans << endl;
return 0;
}
Summary
是一場很有趣的 \(\textrm{div 2}\),雖說是中國場但沒有什么中國 \(\textrm{OI}\) 的氣息(指數據結構、多項式等)。考察的數學知識點較多,感覺 \(\textrm{PJ}\) 選手也能做起來友好的樣子。
我自己要反思一點是:\(\rm E\) 其實並不算太難,卻卡了我很久,有兩點原因:
- 對自己沒有信心,高估 \(\textrm{2E}\) 難度,導致我想了半個小時沒有想出來就開始慌張。以至於算分塊復雜度的時候把質數數量看成了 \(10^5\),均值不等式一分析,詢問次數不夠……就更加慌張,還好最后發現了問題。
- 對於交互題的不熟練,我測試樣例就用了很久時間。交互題的詢問什么的應該封裝到一個函數里,這樣子可以方便自己寫交互庫自己測試。我因為沒有調試導致損失了 \(150\) 分,不然的話就可以到 \(\textrm{rank5}\) 了。