2021,6,10 xjzx 模擬考試
pts: 100
T1: 100
T2: 0
T3: 0
吐槽:xj 中學的神仙題目,T1 貪心跑過了正解的 dp /se
T1
Strategy
遊戲中有 \(n\) 個敵人,面對第 \(i\) 個敵人,三種解決方案
- 花 \(attack_i\) 的代價主動進攻,此技能最多用 \(k\) 次
- 花 \(define_i\) 的代價防禦,此技能可以用無數次
- 和該敵人結盟,此技能只能用一次
給定每個敵人的 \(attack_i\) 和 \(define_i\) 以及最多的攻擊次數 \(k\) ,求出和第 \(i\) 個盟友結盟的情況下,在這一輪的最小花費
\(n \leq 4000\)
solution
貪心
常用策略:考慮敵人的價效比 \((define_i - attack_i)\)
如果一個敵人的 \(D - A\) 比較大的話,會優先考慮進攻 (在次數限制範圍之內)
所以對每個敵人的 \(D - A\) 排序
然後列舉盟友,如果是盟友啥也不動就好
排完序的前 \(n - k\) 個敵人一定選擇防守,對它們沒機會進攻
對後 \(k\) 個選擇進攻或防守
時間複雜度:\(O(n^2)\)
std 複雜度 \(O(n^2log~n)\) ? ?
code
namespace Ariel_{ struct node{int id, num;}E[N]; bool cmp(node a, node b) {return a.num < b.num;} int n, k, a[N], d[N], sum, Ans, p, o; void main(){ n = read(), k = read(); for (int i = 1; i <= n; i++) a[i] = read(), d[i] = read(), sum += a[i]; for (int i = 1; i <= n; i++) E[i].num = d[i] - a[i], E[i].id = i; sort (E + 1, E + n + 1, cmp); for (int i = 1; i <= n; i++) { Ans = sum - a[i], p = 1, o = 1; while (o < n - k) { if (E[p].id != i) Ans += E[p].num, o++; p++; } while (p <= n) { if (E[p].id != i) if (E[p].num < 0) Ans += E[p].num; else break; p++; } printf("%lld ", Ans); } } }
T2
easy LCA
一棵節點為 \(n\) 的樹,給定一個長度為 \(n\) 的排列 \(p\)
定義連續子段的 \(p_{l,r}\) 的權值為 \(val[l,r] = depth[lca(p_l, p_{l + 1}…p_r)]\) (這段序列所有點的 \(lca\) 的深度)
求出所有 \(n * (n + 1)/2\) 的連續欄位的權值之和 \((\sum_{i = 1}^{i = n}\sum_{j = i}^nval[i, j])\)
根節點的深度為 \(1\)
\(n\leq 6*10^5\)
\(solution\)
首先 \(LCA\) 滿足單調性,也就是連續一段區間的 \(LCA\)
所以把所有相鄰節點的 \(LCA\) 都求出來,也就是序列 \(l\)
\(l_i\) 表示 \(nxtLCA_{a_i, a_{i + 1}}\)
對於任意連續 \(k\) 個節點,我們列舉一個 \(l_i\) ,算出它左邊第一個深度小於它的節點 \((l_j)\) 和右邊深度第一個小於它的節點 \(l_k\) 那麼這段區間內的 \(LCA\) 就都是 \(l_i\) 了
這個可以用單調棧維護
namespace STACK{
stack<int> s;
//計算左邊界
void calc_L(){
for (int i = 1; i < n; i++){
while(!s.empty() && l[s.top()] >= l[i]) R[s.top()] = i - 1, s.pop();
s.push(i);
}
while(!s.empty()) R[s.top()] = n - 1, s.pop();
}
//計算右邊界
void calc_R(){
for (int i = n - 1; i >= 1; i--){
while(!s.empty() && l[i] < l[s.top()]) L[s.top()] = i + 1, s.pop();//左邊界
s.push(i);
}
while(!s.empty()) L[s.top()] = 1, s.pop();//多餘的情況
}
}
所以這段區間的答案就為 \(((l_i-l_j+1)*(l_k-l_i+1)*dep[l_i])\)
時間複雜度為 \(O(n logn)\) (求相鄰 \(LCA\) )
code
\(LCA\) 用樹剖寫滴,可能有點長 emm
/*
work by:Ariel_
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
#include <algorithm>
#define int long long
using namespace std;
const int N = 1200010;
int read(){
int x = 0,f = 1; char c = getchar();
while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
return x*f;
}
int n, l[N], a[N], dep[N];
int L[N], R[N];
struct edge {int v, nxt;}e[N];
int head[N], cnt;
void add_edge(int u, int v) {
e[++cnt] = (edge){v, head[u]};
head[u] = cnt;
}
namespace LCA{
int fa[N], top[N], siz[N], son[N];
void dfs(int x, int f) {
fa[x] = f, siz[x] = 1, dep[x] = dep[f] + 1;
for (int i = head[x]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == f) continue;
dfs(v, x);siz[x] += siz[v];
if(siz[v] > siz[son[x]]) son[x] = v;
}
}
void dfs2(int x, int tp) {
top[x] = tp;
if(son[x]) dfs2(son[x], tp);
for (int i = head[x]; i; i = e[i].nxt) {
int v = e[i].v;
if (v == fa[x] || v == son[x]) continue;
dfs2(v, v);
}
}
int lca(int x, int y){
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
return x;
}
}
namespace STACK{
stack<int> s;
void calc_L(){
for (int i = 1; i < n; i++){
while(!s.empty() && l[s.top()] >= l[i]) R[s.top()] = i - 1, s.pop();
s.push(i);
}
while(!s.empty()) R[s.top()] = n - 1, s.pop();
}
void calc_R(){
for (int i = n - 1; i >= 1; i--){
while(!s.empty() && l[i] < l[s.top()]) L[s.top()] = i + 1, s.pop();//左邊界
s.push(i);
}
while(!s.empty()) L[s.top()] = 1, s.pop();//多餘的情況
}
}
namespace Ariel_{
int ans = 0;
void main() {
n = read();
for (int i = 1, u, v; i < n; i++){
u = read(),v = read();
add_edge(u, v), add_edge(v, u);
}
for (int i = 1; i <= n; i++) a[i] = read();
LCA::dfs(1, 0), LCA::dfs2(1, 1);
for (int i = 1; i < n; i++) l[i] = dep[LCA::lca(a[i], a[i + 1])];
STACK::calc_L(), STACK::calc_R();
for(int i = 1; i < n; i++) ans += (i - L[i] + 1) * (R[i] - i + 1) * l[i];
for(int i = 1; i <= n; i++) ans += dep[a[i]];
printf("%lld", ans);
}
}
signed main(){
Ariel_::main();
return 0;
}
T3
Scarborough Fair
由 \(n\) 個點和 \(m\) 條無向邊組成的圖 (由於集市中存在橋,故不保證是平面圖),其中第 \(i\) 條道路連線 \(u_i\) ,\(v_i\) 兩點,有 \(w_i\) 的概率是不能通行的。
小 \(W\) 定義一張圖的不方便程度為圖中的聯通塊個數,現在給定集市的地圖,小 \(W\) 希望你能幫他求出這張圖的期望不方便程度
答案對 \(998244353\) 取模
\(n\leq 17\)
solution
狀壓期望 \(dp\) 部分分都不會寫 @ @