20261020


ABC369 G - As far as possible 黄

https://atcoder.jp/contests/abc369/tasks/abc369_g

其实等价于选择 i 个点,最大化最短走法路径

所以我们可以考虑一棵树,显然先选长链总是不亏的,而选完长链后,再选与之前选过的链上的支链,产生的贡献应该是除去原本选过部分的。

如果这里直接写的话,显然是树链剖分的题,think twice

于是可以维护每一个点到最远的叶子的最长距离 $f_u$,而搜索 $u$ 子树时候其他的所有新链,可以简单的维护成增量,存储到一个地方,最后别忘了传入 $f_0$。

排序直接贪心的从大到小选即可

这里要注意,搜完 $u$ 的时候,为什么不传入 $f_u$,因为此时 $f_u$ 是还具有传递性的,因为他的父亲节点还要继续使用其向上传递,此时不能结算,不然会算重贡献。

namespace XK {

  void solve() {
  	ll N; rd(N);
  	V<V<pair<int, int>>> e(N);
  	rep(i, N - 1) {
  		int u, v, w; rd(u, v, w); -- u, -- v;
  		e[u].pb({v, w});
  		e[v].pb({u, w});
  	}

  	V<int> ord, fa(N, -1);
  	auto dfs = [&](this auto dfs, int u, int pa) -> void {
  		fa[u] = pa;
  		ord.pb(u);
  		for(auto [v, w] : e[u]) if(v != pa) {
  			dfs(v, u);
  		}
  	};
  	dfs(0, -1);
  	
  	V<int> cst, f(N);
  	rrep(i, 0, N) {
  		int u = ord[i];
  		ll now = 0;
  		for(auto [v, w] : e[u]) if(v != fa[u]) {
  			ll x = f[v] + w;
  			if(x > now) swap(x, now);
  			if(x > 0) cst.pb(x);
  		}
  		f[u] = now;
  	}
  	cst.pb(f[0]);

  	sort(all(cst)); reverse(all(cst));

  	ll ans = 0;
  	rep(i, N) {
  		if(i < sz(cst)) ans += cst[i];
  		wt(ans * 2);
  	}

  }
};

AGC058 B - Adjacent Chmax 黄

https://atcoder.jp/contests/agc058/tasks/agc058_b

考虑每个点的管辖范围,也就是笛卡尔树

但是这题不需要显式表示

考虑每个点的区间 $[L_i, R_i)$,你可以变或不变,不变就是继承之前的选法,变就是之前的选法在新选法上累加,也就是 $f_{i,j} = \sum_{j\gt k\ge L_i}f_{i-1,k}$

为什么是累加的呢,因为 当你 枚举 $j$ 的时候,其之前的 满足 $L_i \le k \lt j$ 的位置,都可以作为转移到当前边界的次数,这里不区分边界是因为,无论是左右边界,本质都是边界,不影响后续的点选择,因为点权值满足排列。

  void solve() {
  	ll N; rd(N);
  	V<ll> A(N); rd(A); rep(i, N) -- A[i];
  	V<ll> L(N), R(N);
  	rep(i, N) {
  		L[i] = i, R[i] = i + 1;
  	}
  	// cerr << "?" << endl;
  	rep(i, N) {
  		int j = i;
  		while(j > 0 && A[i] > A[j - 1]) L[i] --, j --;
  		j = i + 1;
  		while(j < N && A[i] > A[j]) R[i] ++, j ++;
  	}

#ifdef DEBUG 
  	rep(i, N) {
  		wt(i,":","[",L[i],":",R[i],"]");
  	}	
#endif

  	V<mm> f(N + 1, 0);
  	f[0] = 1;
  	rep(i, N) {
  		V<mm> nf = f;
  		mm n = 0;
  		Rep(j, L[i], R[i]) {
  			n += f[j];
  			nf[j + 1] += n;
  		}
  		f.swap(nf);
  	}
  	wt(f[N].x);
  }

EDPC **M - Candies ** (个人预估:青色)

https://atcoder.jp/contests/dp/tasks/dp_m

显然设计有 $f_{i,j} :=$ 第 $i$ 个点,一共选了 $j$ 蜡烛的方案数.

显然是 $f_{i,j} := \sum_{0\le x \le a_i} f_{i-1,j - x}$,对于 $x\in [0, a_i]$,那这里

其实就是背包转移 套一个 前缀和

  void solve() {
  	ll N, K; rd(N, K);
  	V<mm> f(K + 1, 0);
  	f[0] = 1;
  	rep(_, N) {
  		ll A; rd(A);
  		V<mm> pre(K + 2, 0); pre[0] = 0;
  		rep(i, K + 1) pre[i + 1] = pre[i] + f[i];
  		V<mm> nf(K + 1);
  		rep(i, K + 1) {
  			nf[i] = pre[i + 1];
  			if(i - A >= 0) nf[i] -= pre[i - A]; 
  		}
  		f.swap(nf);
  	}
  	wt(f[K].x);
  }

ABC253 G - Swap Many Times (黄色偏弱,个人预估:蓝色偏弱)

https://atcoder.jp/contests/abc253/tasks/abc253_g

好纯粹的打表题

注意到如果一个连续操作

$(1,2) ... (1, N)$ 的话,实际上等价于变成 $\set{N,1,2,\ldots,N-1}$

所以只要看两边不完整的操作,中间全部按照这个等价操作简化即可,复杂度是 $O(N)$ 的

当然这个连续操作你很容易就能通过打表看出来。