牛客小白月赛112


A. 智乃的天平

点击查看代码
void solve() {
    int a, b, w;
    std::cin >> a >> b >> w;
    if (a == w || b == w || a + b == w || a + w == b || b + w == a) {
    	std::cout << "Yes\n";
    } else {
    	std::cout << "No\n";
    }
}

B. 智乃爬山

循环判断取最大值。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int ans = -1;
    for (int i = 1; i + 1 < n; ++ i) {
    	if (a[i] > a[i - 1] && a[i] > a[i + 1]) {
    		ans = std::max(ans, a[i] - (a[i - 1] + a[i + 1]) / 2);
    	}
    }

    std::cout << ans << "\n";
}

C. 智乃放球

题意:\(n\)个球\(m\)个桶,你要把这些球放到这些桶里,假设第\(i\)个桶放了\(cnt_i\)个球,那么会变成\(cnt_i \% k\)个球。你要使得总球数恰好为\(q\)

一个桶里最多有\(k-1\)个球,那么如果\((n-1)\times m < q\)无解。
那么我们贪心的每个桶放\(k-1\)个球,然后剩下的\(n \% (k-1)\)个球单独放一个桶。那么还剩下\(n-q\)个球,显然这些球不可以改变总球数,那么\(n=q \% k = 0\)

点击查看代码
void solve() {
    int n, m, k, q;
    std::cin >> n >> m >> k >> q;
    if (k == 1) {
    	std::cout << "No\n";
    	return;
    }
    int cnt = (q + k - 2) / (k - 1);
    if (m < cnt) {
    	std::cout << "No\n";
    	return;
    }

    if ((n - q) % k) {
    	std::cout << "No\n";
    	return;
    }

    std::cout << "Yes\n";
}

D. 智乃的“K”叉树

题意:给你一棵树,选一个点作为根,使得儿子最多的点的儿子数最少。

假设没有根,那么我们选\(u\)为根,根的度数不变,其它的的度数减一。那么把所有点的度数存进\(multiset\),然后枚举作为根的节点,它的度数和剩下点的最大度数减一的最大值就是最多的儿子数。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> deg(n);
    for (int i = 1; i < n; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	++ deg[u];
    	++ deg[v];
    }

    std::multiset<int> s;
    for (int i = 0; i < n; ++ i) {
    	s.insert(deg[i]);
    }

    int k = 1e9, ans = 0;
    for (int i = 0; i < n; ++ i) {
    	s.extract(deg[i]);
    	if (std::max(deg[i], *s.rbegin() - 1) < k) {
    		k = std::max(deg[i], *s.rbegin() - 1);
    		ans = i;
    	}

    	s.insert(deg[i]);
    }

    std::cout << k << " " << ans + 1 << "\n";
}

E. 智乃的“凑数”题(Easy Version)

题意:\(n\)个数,\(m\)个询问,把\(n\)个数分为三部分,价值为第一部分的和与第二部分的和的乘积,第三部分则抛弃,求使得价值恰好为\(x\)的方案。

考虑\(dp\)\(f[i][j][k]\)表示前\(i\)个数第一部分的和为\(i\),第二部分的和为\(j\)是否可行,然后\(pre[i][j][k]\)记录前面转移过来的状态。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    const int N = 101;
    std::vector f(n + 1, std::vector(N, std::vector<int>(N)));
    std::vector pre(n + 1, std::vector(N, std::vector<std::pair<int, int>>(N)));
    f[0][0][0] = 1;
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < N; ++ j) {
    		for (int k = 0; k < N; ++ k) {
    			if (!f[i][j][k]) {
    				continue;
    			}

    			f[i + 1][j][k] = f[i][j][k];
    			pre[i + 1][j][k] = pre[i][j][k];
    			if (j + a[i] < N) {
    				f[i + 1][j + a[i]][k] = 1;
    				pre[i + 1][j + a[i]][k] = {j, k};
    			}

    			if (k + a[i] < N) {
    				f[i + 1][j][k + a[i]] = 1;
    				pre[i + 1][j][k + a[i]] = {j, k};
    			}
    		}
    	}
    }

    while (m -- ) {
    	int x;
    	std::cin >> x;
    	std::vector<int> A, B;
    	for (int v = 1; v * v <= x; ++ v) {
    		if (x % v == 0) {
    			if (f[n][v][x / v]) {
    				int i = n, j = v, k = x / v;
    				while (i) {
    					auto & [prej, prek] = pre[i][j][k];
    					if (prej != j) {
    						A.push_back(j - prej);
    					} else if (prek != k) {
    						B.push_back(k - prek);
    					}

    					-- i;
    					j = prej;
    					k = prek;
    				}
    				break;
    			}
    		}
    	}

    	if (A.empty() && B.empty()) {
    		std::cout << "No\n";
    	} else {
    		std::cout << "Yes\n";
    		std::cout << A.size() << " " << B.size() << "\n";
    		for (auto & x : A) {
    			std::cout << x << " ";
    		}
    		std::cout << "\n";

    		for (auto & x : B) {
    			std::cout << x << " ";
    		}
    		std::cout << "\n";
    	}
    }
}
posted @ 2025-03-21 21:00  maburb  阅读(61)  评论(0)    收藏  举报