首页 > 其他分享 >CSP2024-9

CSP2024-9

时间:2024-08-24 16:26:48浏览次数:6  
标签:tmp sz 遍历 int sum CSP2024 le

如此成绩,如何 noip?

A

题意:\(T\) 组询问,每次给出一个正整数 \(n = p^kq^k \le 10^{18}\)。

求非降序列 \(\{a_{m}\}\)(\(m > 1\))的数量,满足 \(\prod a_i = n\)。

非降并不需要真正考虑每个数的顺序,这很不可做。

考虑 \(n\) 的每个因数在序列中的出现次数。

一个长为 \((k + 1)^2 - 2\) 的向量组 \([c_1, c_2 \cdots, c_i, \cdots]\) 可以唯一对应一个序列,这是一个双射。

转化到完全背包模型,\(f_{i, j}\) 表示乘到 \(p^iq^j\) 的方案数。枚举因子 \(p^{i}q^j\),顺序更新 \(p^{x \ge i}q^{y \ge j}\)。

答案只与 \(k\) 有关,瓶颈在于如何快速找 \(k\)。(\(6^{24} > 10^{18}\),所有 \(f\) 可以预处理)

枚举 \(k\),直接调用 pow(1, 1./ k),加 0.5 规避精度问题。

void init() {
	f[0][0] = 1;
	for(int i = 0; i <= 23; ++ i) {
		for(int j = 0; j <= 23; ++ j) {
			if(i || j)
				for(int x = i; x <= 23; ++ x) {
					for(int y = j; y <= 23; ++ y) {
						f[x][y] += f[x - i][y - j];
					}
				}
		}
	}
}
void solve() {
	cin >> n;
	for(int i = 23; i >= 1; -- i) {
		auto x = powl(n, 1./ i); ll y = x + 0.5;
		if(fabsl(x - y) <= eps) {
			cout << f[i][i] - 1 << '\n';
			return;
		}
	}
}

B

题意:从时刻 \(0\) 遍历一棵树,每一时刻只能走一条边。每个点的代价为到达这个点的时刻,\(n \le 10^5\)。

钦定起点(选根),肯定是一棵子树遍历完了再去其他地方。

定义 \(f(i)\) 表示走完 \(i\) 这棵子树的最小代价。

考虑每个儿子 \(j\),从 \(i\) 走到任意 \(j\) 子树内的点都会经过 \((i, j)\) 并使他的代价加 \(1\),因此 \(i\) 对 \(j\) 的额外贡献等于 \(sz_j\)。

已经遍历完的子树 \(k\) 对 \(j\) 中每个点的额外贡献等于在 \(k\) 中经过的时间 \(2 sz_k\)。

\[f(i) \gets f(j) + sz_j (1+ 2\sum_{k} sz_k) \]

\(sz_k\) 会对所有在他之后的子树产生额外贡献,这是不是意味着我们需要按照子树大小升序遍历呢?

不管怎么遍历,数对 \((j, k)\) 对答案的贡献都是 \(2sz_j\cdot sz_k\),因此 \(f(i)\) 可以写成:

\[\sum_{j} \big(f(j) + sz_j\big) + 2\sum_{j, k} sz_j \cdot sz_k \]

换根好像还挺好写的。

#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;

using ll = long long;
constexpr int N = 1e5 + 5;

int n, m, rt, sz[N]; ll f[N], g[N], tmp[N], sum[N], ans = 1e18;
vector<int> G[N];

void dfs(int x, int fa) {
	f[x] = sz[x] = 0;
	for(int y : G[x]) {
		if(y == fa) continue;
		dfs(y, x);
		f[x] += sz[y] + f[y] + 2ll * sz[y] * sz[x];
		sum[x] += f[y];
		tmp[x] += 2ll * sz[y] * sz[x];
		sz[x] += sz[y];
	}
	++ sz[x];
}
void dfs1(int x, int fa) {
	ans = min(ans, g[x]);
	for(int y : G[x]) {
		if(y == fa) continue;
		g[y] = sum[y] + n - 1;
		g[y] += (g[x] - f[y] - sz[y] - 2ll * sz[y] * (n - sz[y] - 1));
		tmp[y] += 2ll * (sz[y] - 1) * (n - sz[y]);
		g[y] += tmp[y];
		dfs1(y, x);
	}
}
int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin >> n;
	for(int i = 1; i <= n - 1; ++ i) {
		int u, v; cin >> u >> v;
		G[u].eb(v);
		G[v].eb(u);
	}
	dfs(1, 0);
	g[1] = f[1], dfs1(1, 0);
	cout << ans;
	return 0;
}

C

题意:\((x_1, \cdots, x_m)\) 是好的,当且仅当对于 \(1 < j \le m\),要么有 \(x_i = x_{i - 1} + 1\),要么存在 \(k \le j < i\) 使得 \(x_i = x_kx_j\)。

D

标签:tmp,sz,遍历,int,sum,CSP2024,le
From: https://www.cnblogs.com/Luxinze/p/18377900

相关文章