# 113學年度建國中學校內資訊能力競賽 複試題解 ---- ## 難度 $C<A<D<B<E$ --- # pA PCC 問問題 ## Setter : PCC ---- 連續給分是因為怕同分比序 ~~順便出最近兩年校內賽都沒出現的互動題~~ ---- ## Subtask 1 : $N \le 10$ 其實我也不知道怎麽做到的 應該是寫subtask 2寫爛就會只有subtask 1? ---- ## Subtask 2 : 41./100 看一下範例是問 $(0,0,n-1)$ 想到可以問兩個一樣的人 於是可以觀察到問 $i,i,j$ 可以比較兩個數字的大小 如果Ask(i,i,j) = 0,則 $p_i \le p_j$ 有比較函式了耶 ---- sort(p.begin(),p.end(),cmp) ---- 蛤怎麽沒過??? 因為 std::sort 沒有保證比較次數 用 std::stable_sort ---- ## Subtask 2 : 68./100 如果已知 $p_i < p_j$ ,那問 $(i,j,j)$ 可以知道 $p_i \oplus p_j$ 可以花 $N$ 次找出最小的人 之後花 $N$ 次知道各人跟 $0$ 的 xor ---- ## Subtask 2 : 78./100 比大小的時候問了什麼? $(i,i,j)$ 知道兩個人的xor時問了什麼? $(i,i,j)$ 感覺一樣欸 ---- 壓一下次數,令目前記到的最小值的index為mn 如果問 $(mn,mn,i) \neq 0$ 那我們同時會知道 $p_{mn} > p_i \land p_{mn} \oplus p_i$ 如果 $(mn,mn,i) = 0$ ,那我們再問一次 $(mn,i,i)$ 知道兩個人的 xor ---- 找答案的時候只要把已知的兩個人xor接邊,,從 $p_{mn} = 0$ 開始 DFS 即可 ---- 這樣看起來是滿滿的 $2N$ 次? 只要整個排列是反序的就會跑滿 ---- judge 是 non-adaptive ---- 如果我們random決定先問 $(mn,mn,i)$ 還是 $(mn,i,i)$ ,那我們有一半的機率戳到非零的那一個 期望次數 $\frac{1}{2} \times N+\frac{1}{2} \times 2N = 1.5N$ 理論上會有 78.多分 ---- ## Subtask 2 : 100/100 一樣用到 judge 是 non-adaptive ---- 先 random shuffle 以免被刻意構造的測資卡 有哪些情況問 $(mn,i,i) = 0$ ? ---- 當最小值變小的時候 ---- 這東西大概在隨機的陣列期望值是幾次? Ans : $\log N$ 層級次數 (proof is left as an exercise) 提示:分開考慮各個數字的貢獻 ---- 次數: $N+\log N$ 滿分! ---- 希望不會有人因為這題 $< 1$ 分的差距下去... --- # pB 補牙 ## Setter : guagua0407 ---- ## Subtask 1:$n,q\leq 5000$ 暴力$O(nq)$做 ---- ## Subtask 2:$t=1$ 基本上是[cses](https://cses.fi/problemset/task/2416) 其中一種做法是離線+bit ---- ## full 考慮一顆線段樹存$[l,r]$的: - 最大的$a_i$ - $\sum a_i$ - $[l,r]$中把$[l,m]$變好的最小操作次數 ![image](https://hackmd.io/_uploads/rypoTJt0C.png) ---- 怎麼build? 前兩項都很好做 問題是最後一項 把$[l,m]$和$[m+1,r]$合併時要看的是右邊給左邊的 左邊的人可能要抬到右邊最大的人那麼高 ---- 假設右邊最大的人是$X$ 來看怎麼算$[l,m]$ - 如果$[l,m]$最大的人$<X$ 那就是$X\cdot len-\sum a_i$ - 不然的話看$[l,m]$的左小孩有沒有$<X$ - 如果有:那右邊的人都會抬到$X$,然後往左邊遞迴 - 反之:左小孩都不會動,遞迴右邊 這樣能在$O(n\log^2n)$建好 ---- 那算答案呢? 其實差不多 就把$[l,r]$分成$\log$個區間 從右往左用類似的方法算 可以寫在遞迴裡也可以真的把$\log$個人取出來 這樣會是$O((n+q)\log^2 n)$ ---- Code ```cpp= //#pragma GCC optimize("O3") #include <bits/stdc++.h> using namespace std; #define ll long long #define pii pair<int,int> #define f first #define s second #define all(x) x.begin(),x.end() #define _ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; void setIO(string s) { freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout); } struct node{ ll ans,sum; int maxY; node(){ ans=0; sum=0; maxY=-1; } }; const int mxn=2e5+5; vector<node> segtree(mxn*4); vector<pair<pair<int,int>,int>> intervals; int n,q; bool tf=false; ll cut(int l,int r,int v,int val){ if(l==r){ return (val>segtree[v].maxY?val-segtree[v].maxY:0); } int mid=(l+r)/2; if(val>segtree[v*2+1].maxY) return cut(l,mid,v*2,val)+1ll*val*(r-mid)-segtree[v*2+1].sum; else return segtree[v].ans+cut(mid+1,r,v*2+1,val); } void pull(int l,int r,int v){ segtree[v].maxY=max(segtree[v*2].maxY,segtree[v*2+1].maxY); segtree[v].sum=segtree[v*2].sum+segtree[v*2+1].sum; int mid=(l+r)/2; segtree[v].ans=cut(l,mid,v*2,segtree[v*2+1].maxY); } void update(int pos,int val,int l=0,int r=n-1,int v=1){ if(l==r){ segtree[v].maxY=val; segtree[v].ans=0; segtree[v].sum=val; return; } int mid=(l+r)/2; if(pos<=mid) update(pos,val,l,mid,v*2); else update(pos,val,mid+1,r,v*2+1); pull(l,r,v); } void query(int tl,int tr,int l=0,int r=n-1,int v=1){ if(r<tl or tr<l){ return; } if(tl<=l and r<=tr){ intervals.push_back({{l,r},v}); return; } int mid=(l+r)/2; query(tl,min(mid,tr),l,mid,v*2); query(max(mid+1,tl),tr,mid+1,r,v*2+1); } int main() {_ cin>>n>>q; vector<int> a(n); for(int i=0;i<n;i++){ cin>>a[i]; } for(int i=0;i<n;i++){ update(i,a[i]); } for(int i=0;i<q;i++){ int t; cin>>t; if(t==0){ int id,x; cin>>id>>x; id--; a[id]=x; update(id,a[id]); } else{ int l,r; cin>>l>>r; l--,r--; query(l,r); ll ans=0; int maxY=-1; while(!intervals.empty()){ ans+=cut(intervals.back().f.f,intervals.back().f.s,intervals.back().s,maxY); maxY=max(maxY,segtree[intervals.back().s].maxY); intervals.pop_back(); } cout<<ans<<'\n'; } } return 0; } //maybe its multiset not set //yeeorz //diaoborz ``` --- # pC SJY 的國際刷牙奧林匹亞難題 ## Setter : becaido ---- ## Subtask 1:$n=1$ ---- 等價求最大連續和 $O(m^2)$ 或 $O(m)$ 都會過 ---- ## Subtask 2:恰好存在一個 $a_{i,j}<0$,其餘都 $\ge 0$ ---- $<0$ 的那個只會有拿或不拿 拿的話一定是把全部人都加起來最好 不拿的話是拿上面全部跟下面全部,再看左邊跟右邊哪個比較大 ---- 要注意 $m=1$ 的 Case ---- ## Subtask 3:$n,m\le 70$ ---- 令 $dp_{i,l,r}$ 是刷了前 $i$ 排牙齒 且第 $i$ 排刷 $[l,r]$ 的最大值 ---- 轉移可以從 $dp_{i-1}$ 枚舉區間 複雜度 $O(nm^4)$ 可以通過 記 $dp$ 值的前後綴 $\max$ 可以優化到 $O(nm^3)$ ---- ## Subtask 4:無其他限制 ---- 第 $i$ 排的區間被 $i-1$ 排包含的情況 $[l,r]$ 可以從 $[l,r+1]$ 加上一段 $dp_{i-1,1,r}\sim dp_{i-1,l,r}$ 轉移過來 ---- 第 $i$ 排包含第 $i-1$ 排的情況類似 維護 $dp$ 值的前後綴 $\max$ 時間複雜度 $O(nm^2)$ ---- 空間 $O(nm^2)$ 會超過記憶體限制 可以用滾動的方式做到 $O(m^2)$ ---- Code ```cpp= #include <bits/stdc++.h> using namespace std; using ll = long long; const ll INF = 1e18; const int N = 505; int n, m; ll ans, sum[N][N], dp[N][N], pre_mx[N][N], suf_mx[N][N]; int main() { ios::sync_with_stdio(false), cin.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { int x; cin >> x; sum[i][j] = sum[i][j - 1] + x; } } for (int i = 1; i <= n; i++) { for (int r = 1; r <= m; r++) { pre_mx[r][0] = -INF; for (int l = 1; l <= r; l++) { pre_mx[r][l] = max(pre_mx[r][l - 1], dp[l][r]); } suf_mx[r][r + 1] = -INF; for (int l = r; l >= 1; l--) { suf_mx[r][l] = max(suf_mx[r][l + 1], dp[l][r]); } } for (int l = 1; l <= m; l++) { ll mx = -INF; fill(dp[l] + 1, dp[l] + m + 1, -INF); for (int r = l; r <= m; r++) { mx = max(mx, suf_mx[r][l]); dp[l][r] = max(dp[l][r], mx + sum[i][r] - sum[i][l - 1]); } mx = -INF; for (int r = m; r >= l; r--) { mx = max(mx, pre_mx[r][l]); dp[l][r] = max(dp[l][r], mx + sum[i][r] - sum[i][l - 1]); } } } ans = -INF; for (int l = 1; l <= m; l++) { ans = max(ans, *max_element(dp[l] + 1, dp[l] + m + 1)); } cout << ans << '\n'; } ``` --- # pD 小祥愛賽車 ## Setter : owoovo ---- ## Subtask 1:$a_i=1$ 正常的dijkstra ---- ## Subtask 2:$a_i遞減$ 起點和終點反過來就變正常的dijkstra ---- ## Subtask 3:$一條鍊$ 對答案二分搜 掃一遍$L$去往前走 ---- ## Subtask 4:$N,M,L\leq 3000$ 拆點,設$v_{i,j}$是走$j$步後到$i$ 好好連邊之後就可以開心dijkstra ---- ## Subtask 4:$N,M\leq 3000$ 出題的人忘了 ---- ## full 看到$\min$就想二分搜答案了 發現到你在判斷的時候其實是在問說: 只走一些好的邊時,可不可以走到$n$ ---- 去設$dis_i$是走到$i$最少需要用到多長$L$的前綴 在這上面做dijkstra 現在問題只剩下轉移 ---- 轉移其實在問一個後綴裡最前面$\leq x$的位置 可以線段樹上二分搜(好像有卡到常 抱歉..) 賽中好像也有人是用sparse table ---- 發現到可以不用邊去找$L$, 而是用$L$去看他可以轉移的邊 就可以用一個迴圈取代資結,超賺 會是$O((N+M+L)\cdot\log M\cdot\log C)$之類的 ---- Code ```cpp= #include<bits/stdc++.h> #define ll long long #define F first #define S second using namespace std; const ll e18=1e18; int n,m,L,vis[100010]; int a[1000010]; vector<pair<int,int>> e[100010]; bool check(ll c){ for(int i=1;i<=n;i++)vis[i]=0; priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>> pq; vis[1]=1; for(auto x:e[1]){ pq.push({x.S,x.F}); } for(int i=0;i<L;i++){ vector<int> id; while(!pq.empty()&&pq.top().F<=c/a[i]){ auto [x,y]=pq.top(); pq.pop(); if(vis[y]==0){ id.push_back(y); vis[y]=1; } } for(auto x:id){ for(auto E:e[x]){ if(vis[E.F]==0){ pq.push({E.S,E.F}); } } } } return vis[n]; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>m>>L; for(int i=0;i<L;i++)cin>>a[i]; for(int i=0;i<m;i++){ int u,v; ll w; cin>>u>>v>>w; e[u].push_back(make_pair(v,w)); e[v].push_back(make_pair(u,w)); } ll l=1,r=e18; while(l!=r){ ll m=(l+r)>>1; if(check(m)){ r=m; }else{ l=m+1; } } cout<<l<<"\n"; return 0; } ``` --- # pE 小祥愛騎車 ## Setter : pacybwoah ---- ## 簡短題敘 給兩個長度為 $N$ 的序列 $A,B$,多筆詢問 $[L,R]$ 問 $\max\limits_{L \leq i \leq j \leq R}(\max\limits_{i \leq v \leq j} A_v - \max\limits_{i \leq v \leq j} B_v + K \cdot (j - i + 1))$ ---- ## Subtask 1:$N,Q \leq 100$ 對每筆詢問枚舉所有 $[i,j]$ 算答案,複雜度 $O(QN^3)$ ---- ## Subtask 2:$N \leq 2000$ $N$ 很小,可以預處理所有可能詢問的答案 ---- 定義 $dp_{l,r}$ 為 $[l,r]$ 這筆詢問的答案,則他有可能: - 直接選 $[l,r]$ 這段區間 - 選比較小的區間:此時這段區間會被 $[l,r-1]$ 或 $[l+1,r]$ 覆蓋到,因此可以取 $\max(dp_{l,r-1},dp_{l+1,r})$ 詢問時直接查表回答,複雜度 $O(n^2 + q)$ ---- ## Subtask 3:$K=0$ 當長度對答案沒有影響時,可以注意到:對於一段區間 $[l,r]$,假設 $A$ 的 max 出現在 $v$,那其實可以直接選 $[v,v]$ 就好,因為 $\max A$ 不變,而且 $\max B$ 不會變大 ---- 因此問題其實就是問 $\max\limits_{l \leq i \leq r}(A_i-B_i)$,可以用你最喜歡的 RMQ 資結解,複雜度 $O(N + QlogN)$ 或 $O(NlogN + Q)$ ---- ## Subtask 4:$Q=1$ 要進入比較通靈的部分了 max 的特質是很難刪東西,會發現很難維護 要怎麼樣才能只用合併算出答案呢? ---- 考慮分治! 定義 $f(l, r)$ 為算出 $[l,r]$ 這段區間答案的函數,每次遞迴要 - 呼叫 $f(l, mid)$ 跟 $f(mid + 1,r)$ - 算出跨過 mid 的區間中的最大好感度 ---- 先定義 maxA, maxB 兩個陣列,代表每個位置到 mid 這段區間($[i,mid]$ 或 $[mid + 1,i]$)的最大 A, B 那題目就變成:想要在 $[l,mid]$ 跟 $[mid + 1,r]$ 分別抓 $i$ 跟 $j$,使得 $\max(\text{maxA[i]},\text{maxA[j]})$ $-\max(\text{maxB[i]},\text{maxB[j]})+K*(j-i+1)$ 最大 ---- 可以分成兩種情況: 1. maxA 跟 maxB 的最大值出現在同一側 2. maxA 跟 maxB 的最大值出現在不同側 ---- 先講解同側的 case: 枚舉左邊的位置當作 $i$ ,可以用雙指針找到右邊滿足 $\text{maxA[i]} \geq \text{maxA[j]}$ 而且 $\text{maxB[i]} \geq \text{maxB[j]}$ 的人 ---- 因為 maxA 跟 maxB 都已經確定,因此選最右邊的人長度最長 = 最好 記得右邊的位置也要做同樣的事 ---- 異側的 case: 可以做類似的事情,但有兩種不同的枚舉方法: - 枚舉當 maxA 的人 - 枚舉當 maxB 的人 ---- - 如果枚舉當 maxA 的人,那要在另外一邊找(長度 - maxB)最大的人 - 如果枚舉當 maxB 的人,那要在另外一邊找(長度 + maxA)最大的人 ---- 注意到只有第二種方法會有單調性! 單調性:因為長度跟 maxA 都非嚴格遞增,所以對於左邊的人來說,可以直接選符合條件且最右邊的人配他 ---- 所以小心分 case 並好好雙指針就可以處理答案了!複雜度 $O(nlogn)$ ---- ## Subtask 5:無特別限制 線段樹是什麼? ---- 線段樹是「把分治的結果儲存起來」的資料結構 ---- 要儲存什麼東西,才能回答區間詢問? ---- 在一般用線段樹回答區間詢問的時候,會分成三種狀況: - 詢問區間完全包含節點區間 - 詢問區間跟節點區間不相交 - 詢問區間與節點區間部分重疊 ---- 第一種和第二種狀況很好處理,麻煩的是第三種狀況 為了方便,我們把線段樹上的目前節點叫做 $[l,r]$ ,把重疊的部分叫做 $[L,R]$ ---- 分治的時候做的事是:枚舉 $[l,mid]$ 中的人,用雙指針找到 $[mid,r]$ 中最右邊且滿足條件的人 我們可以先對每個人紀錄「最右邊且滿足條件的人」,但問題是這個人有可能比 $R$ 大 ---- 注意到對於一個左邊的人,如果他的「最右邊且滿足條件的人」比 $R$ 大的話,那他會想直接拿 $R$ 當右邊的人。 ---- 同時,「最右邊且滿足條件的人」會隨著左邊的人遞減而遞增。這代表我們可以用二分搜找到分界點 $x$,使得 $[L,x]$ 的「最右邊且滿足條件的人」都超過 $R$,而 $[x+1,mid]$ 的「最右邊且滿足條件的人」都不超過 $R$ ---- 對於 $[L,x]$ 中的人,因為右端點都是 $R$ ,所以可以先用一個存「左半邊貢獻」的線段樹查出他們的貢獻最大值,再加上 $R$ 的貢獻 對於 $[x+1,mid]$ 中的人,因為右端點都包含在詢問區間裡,所以可以直接用存「最大貢獻」的線段樹查出貢獻最大值 ---- 這樣就做完了!在一個線段樹的節點中,總共需要存四個線段樹,對應到(分治時的兩種狀況)$\cdot$(查詢貢獻時的兩種狀況) 詢問時在一個節點中需要花 $O(logN)$ 的時間,所以時間複雜度是 $O(NlogN + Qlog^2N)$ ---- 空間複雜度是 $O(NlogN)$,但是因為要存很多東西所以記憶體會很大 我有特別開到 1024 MB,但如果想要壓記憶體的話可以用 [這篇 blog 的技巧](https://codeforces.com/blog/entry/119104) 把詢問離線,在分治時一起算答案,這樣子空間複雜度會變成 $O(N)$ ---- Code ```cpp= #include<iostream> #include<vector> #include<algorithm> #include<utility> using namespace std; typedef long long ll; const ll mininf = -1e18; ll k; vector<ll> tmp; vector<pair<ll, ll>> vec; struct st{ vector<ll> seg; void build(int l, int r, int ind){ if(l == r){ seg[ind] = tmp[l]; } else{ int mid = (l + r) >> 1; build(l, mid, ind * 2); build(mid + 1, r, ind * 2 + 1); seg[ind] = max(seg[ind * 2], seg[ind * 2 + 1]); } } st(int l, int r){ int n = r - l + 1; if(n == 0) return; seg.resize(4 * n + 4); build(l, r, 1); } ll query(int l, int r, int start, int end, int ind){ if(r < start || end < l) return mininf; if(start <= l && r <= end) return seg[ind]; int mid = (l + r) >> 1; return max(query(l, mid, start, end, ind * 2), query(mid + 1, r, start, end, ind * 2 + 1)); } }; struct node{ ll ans; vector<int> ab, ba; vector<ll> maxA, maxB; st abnorm, banorm, abhalf, bahalf; node(): abnorm(1, 0), banorm(1, 0), abhalf(1, 0), bahalf(1, 0){} }; vector<node> seg; void build(int l, int r, int ind){ if(l == r){ seg[ind].ans = vec[l].first - vec[l].second + k; return; } int mid = (l + r) >> 1; build(l, mid, ind * 2); build(mid + 1, r, ind * 2 + 1); seg[ind].ans = max(seg[ind * 2].ans, seg[ind * 2 + 1].ans); int len = r - l + 1; seg[ind].ab.resize(len); seg[ind].ba.resize(len); seg[ind].maxA.resize(len); seg[ind].maxB.resize(len); for(int i = mid; i >= l; i--) seg[ind].maxA[i - l] = max(seg[ind].maxA[i + 1 - l], vec[i].first), seg[ind].maxB[i - l] = max(seg[ind].maxB[i + 1 - l], vec[i].second); seg[ind].maxA[mid + 1 - l] = vec[mid + 1].first, seg[ind].maxB[mid + 1 - l] = vec[mid + 1].second; for(int i = mid + 2; i <= r; i++) seg[ind].maxA[i - l] = max(seg[ind].maxA[i - 1 - l], vec[i].first), seg[ind].maxB[i - l] = max(seg[ind].maxB[i - 1 - l], vec[i].second); int ptr = mid; for(int i = mid; i >= l; i--){ while(ptr < r && seg[ind].maxA[ptr + 1 - l] <= seg[ind].maxA[i - l] && seg[ind].maxB[ptr + 1 - l] <= seg[ind].maxB[i - l]) ptr++; seg[ind].ab[i - l] = ptr; if(ptr <= mid) tmp[i] = mininf; else tmp[i] = seg[ind].maxA[i - l] - seg[ind].maxB[i - l] + k * (ptr - i + 1); seg[ind].ans = max(seg[ind].ans, tmp[i]); } ptr = mid + 1; for(int i = mid + 1; i <= r; i++){ while(ptr > l && seg[ind].maxA[ptr - 1 - l] <= seg[ind].maxA[i - l] && seg[ind].maxB[ptr - 1 - l] <= seg[ind].maxB[i - l]) ptr--; seg[ind].ab[i - l] = ptr; if(ptr > mid) tmp[i] = mininf; else tmp[i] = seg[ind].maxA[i - l] - seg[ind].maxB[i - l] + k * (i - ptr + 1); seg[ind].ans = max(seg[ind].ans, tmp[i]); } seg[ind].abnorm = st(l, r); ptr = mid; for(int i = mid; i >= l; i--){ while(ptr < r && seg[ind].maxB[ptr + 1 - l] <= seg[ind].maxB[i - l]) ptr++; seg[ind].ba[i - l] = ptr; if(ptr <= mid) tmp[i] = mininf; else tmp[i] = seg[ind].maxA[ptr - l] - seg[ind].maxB[i - l] + k * (ptr - i + 1); seg[ind].ans = max(seg[ind].ans, tmp[i]); } ptr = mid + 1; for(int i = mid + 1; i <= r; i++){ while(ptr > l && seg[ind].maxB[ptr - 1 - l] <= seg[ind].maxB[i - l]) ptr--; seg[ind].ba[i - l] = ptr; if(ptr > mid) tmp[i] = mininf; else tmp[i] = seg[ind].maxA[ptr - l] - seg[ind].maxB[i - l] + k * (i - ptr + 1); seg[ind].ans = max(seg[ind].ans, tmp[i]); } seg[ind].banorm = st(l, r); for(int i = l; i <= mid; i++) tmp[i] = seg[ind].maxA[i - l] - seg[ind].maxB[i - l] + k * (mid - i + 1); for(int i = mid + 1; i <= r; i++) tmp[i] = seg[ind].maxA[i - l] - seg[ind].maxB[i - l] + k * (i - mid); seg[ind].abhalf = st(l, r); for(int i = l; i <= mid; i++) tmp[i] = -seg[ind].maxB[i - l] + k * (mid - i + 1); for(int i = mid + 1; i <= r; i++) tmp[i] = -seg[ind].maxB[i - l] + k * (i - mid); seg[ind].bahalf = st(l, r); } ll query(int l, int r, int start, int end, int ind){ if(r < start || end < l) return mininf; if(start <= l && r <= end) return seg[ind].ans; int mid = (l + r) >> 1; ll res = max(query(l, mid, start, end, ind * 2), query(mid + 1, r, start, end, ind * 2 + 1)); if(end <= mid || mid + 1 <= start) return res; start = max(start, l); end = min(end, r); int bsl = start, bsr = mid + 1, bsmid; while(bsl < bsr){ bsmid = (bsl + bsr) >> 1; if(seg[ind].ab[bsmid - l] <= end) bsr = bsmid; else bsl = bsmid + 1; } if(bsl > start) res = max(res, seg[ind].abhalf.query(l, r, start, bsl - 1, 1) + k * (end - mid)); if(bsl <= mid) res = max(res, seg[ind].abnorm.query(l, r, bsl, mid, 1)); bsl = start, bsr = mid + 1; while(bsl < bsr){ bsmid = (bsl + bsr) >> 1; if(seg[ind].ba[bsmid - l] <= end) bsr = bsmid; else bsl = bsmid + 1; } if(bsl > start) res = max(res, seg[ind].bahalf.query(l, r, start, bsl - 1, 1) + seg[ind].maxA[end - l] + k * (end - mid)); if(bsl <= mid) res = max(res, seg[ind].banorm.query(l, r, bsl, mid, 1)); bsl = mid, bsr = end; while(bsl < bsr){ bsmid = ((bsl + bsr) >> 1) + 1; if(seg[ind].ab[bsmid - l] >= start) bsl = bsmid; else bsr = bsmid - 1; } if(bsl >= mid + 1) res = max(res, seg[ind].abnorm.query(l, r, mid + 1, bsl, 1)); if(bsl < end) res = max(res, seg[ind].abhalf.query(l, r, bsl + 1, end, 1) + k * (mid - start + 1)); bsl = mid, bsr = end; while(bsl < bsr){ bsmid = ((bsl + bsr) >> 1) + 1; if(seg[ind].ba[bsmid - l] >= start) bsl = bsmid; else bsr = bsmid - 1; } if(bsl >= mid + 1) res = max(res, seg[ind].banorm.query(l, r, mid + 1, bsl, 1)); if(bsl < end) res = max(res, seg[ind].bahalf.query(l, r, bsl + 1, end, 1) + k * (mid - start + 1) + seg[ind].maxA[start - l]); return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; cin >> k; tmp.resize(n + 1); vec.resize(n + 1); for(int i = 1; i <= n; i++) cin >> vec[i].first; for(int i = 1; i <= n; i++) cin >> vec[i].second; seg.resize(4 * n + 4, node()); build(1, n, 1); int q; cin >> q; for(int i = 0; i < q; i++){ int l, r; cin >> l >> r; cout << query(1, n, l, r, 1) << "\n"; } } ``` --- # Some stats ---- ## 場內 + 場外首殺 pA:dreamoon @ 10:09:32 pB:dreamoon @ 11:19:05 pC:dreamoon @ 09:21:27 pD:dreamoon @ 09:41:37 pE:x ---- ## 場內首殺 pA:ckfin_026 @ 10:33:41 pB:ckfin_023 @ 11:56:26 pC:ckfin_023 @ 09:37:44 pD:ckfin_024 @ 10:41:46 pE:x ---- ## pA 場內分佈 100:3 68:3 41:4 20:7 ---- ## pB 場內分佈 100:1 40:3 13:20 ---- ## pC 場內分佈 100:4 39:1 28:17 12:2 ---- ## pD 場內分佈 100:1 70:1 28:1 21:1 7:6 ---- ## pE 場內分佈 62:1 47:1 33:1 22:1 21:1 15:1 7:10 ---- ## 場內各題平均 pA:26.09 pB:15.48 pC:30.29 pD:8.42 pE:8.71 Total:89.00
{"title":"建中資訊校內賽複賽題解","slideOptions":"{}","description":"A<B<C \\approx D \\approx E","contributors":"[{\"id\":\"80534ff6-e4c7-48c5-88c7-d13ac225a4c2\",\"add\":5332,\"del\":85},{\"id\":\"44be8f10-8a3c-4f95-9084-6a5f98bc8bf5\",\"add\":1278,\"del\":31},{\"id\":\"7816456f-346c-479d-bcac-746977dfdcea\",\"add\":9149,\"del\":72},{\"id\":\"52026c9b-045c-4e64-9cc6-78986ed19085\",\"add\":2120,\"del\":3}]"}
    476 views
   owned this note