比赛链接:

https://codeforces.com/contest/1646

C. Factorials and Powers of Two

题目大意:

\(n\) 最少能由几个不同的 powerful 数组成,定义 \(2^d\) 和 d! 都是 powerful 数。

思路:

一个数肯定能由几个 \(2^d\) 组成,而 \(n\) 的数据范围是 1e12,所以我们可以暴力跑出所有 d! ,然后用 \(dfs\) 找所有小于 \(n\) 的组合,将剩下的数用二进制表示就可以了。

代码:

#include <bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(), (x).end()
#define LL long long
#define pb push_back
LL T = 1, n, ans;
vector <LL> num;
void init(){
	LL k = 1;
	for (LL i = 1; i <= 15; i++){
		k = k * i;
		num.pb(k);
	}
}
void dfs(LL now, int p, LL k){
	if ( p >= num.size() || now > n ) return;
	ans = min(ans, k + __builtin_popcountll(n - now) );
	dfs(now + num[p], p + 1, k + 1);
	dfs(now, p + 1, k);
	
}
void solve(){
	scanf("%lld", &n);
	ans = __builtin_popcountll(n);
	dfs(0, 0, 0);
	cout << ans << "\n";
}
int main(){
	init();
	cin >> T;
	while(T--)
		solve();
	return 0;
}

D. Weight the Tree

题目大意:

一个有 \(n\) 个点的树,每一个点有一个权重,当一个点的权重等于周围邻点权重之和时,它被称作 \(good\) 点,现在要让该树的 \(good\) 点的数量最多并让所有点的权重之和最小,给出一个对每个点赋值的方案。

思路:

显然,除了树上只有两个点的情况外,不可能出现邻近的两个点都是 \(good\) 点。
由此可以想到 \(dp\) 去做,每个点有两个属性,是 \(good\),或者不是 \(good\) 点,用 \(dp[i][0]\) 表示该点非 \(good\) 状态下的最佳方案和 \(dp[i][1]\) 表示该点 \(good\) 的时候的最佳方案。又因为要使权重之和最小,每个 \(dp\) 状态要记录两个值,点数以及权重之和
考虑一下每个点要赋什么值才能使权重之和最小,因为权重不能小于 1,所以每个非 \(good\) 点都赋 1,\(good\) 点则赋邻点数量的值就行。
当当前点是 \(good\) 时,只能从邻近的非 \(good\) 点转移过来。
当当前点不是 \(good\) 时,它可以从邻近的 \(good\) 或者非 \(good\) 点转移过来。
由此得到转移方程,然后通过递归,求出答案。
接着再通过一遍遍历,进行赋值。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define IOS() ios::sync_with_stdio(false);cin.tie(0);
#define pb push_back
#define fi first
#define se second
#define pii pair <int, int>
pii dp[N][2];
int n, m;
vector <int> e[N], ans(N);
pii operator+ (pii a, pii b){
	return {a.fi + b.fi, a.se + b.se};
}
void dfs1(int u, int fa){
	dp[u][0] = {0, -1};
	dp[u][1] = {1, -(int)e[u].size()};
	for (auto v : e[u]){
		if ( v == fa ) continue;
		dfs1(v, u);
		dp[u][0] = dp[u][0] + max( dp[v][0], dp[v][1] );
		dp[u][1] = dp[u][1] + dp[v][0];
	}
}
void dfs2(int u, int fa, int c){
	ans[u] = (c ? (int)e[u].size() : 1);
	for (auto v : e[u]){
		if ( v == fa ) continue;
		if ( dp[v][0] > dp[v][1] || c ) dfs2(v, u, 0);
		else dfs2(v, u, 1);
	}
}
int main(){
	IOS();
	cin >> n;
	for (int i = 1; i < n; ++ i){
		int u, v;
		cin >> u >> v;
		e[u].pb(v);
		e[v].pb(u);
	}
	if (n == 2){
		cout << "2 2\n1 1\n";
		return 0;
	}
	dfs1(1, 0);
	if (dp[1][0] > dp[1][1]){
		cout << dp[1][0].fi << " " << -dp[1][0].se << "\n";
		dfs2(1, 0, 0);
	}
	else{
		cout << dp[1][1].fi << " " << -dp[1][1].se << "\n";
		dfs2(1, 0, 1);
	}
	for (int i = 1; i <= n; ++ i)
		cout << ans[i] << " \n"[i == n];
	return 0;
}
posted on 2022-03-05 18:11  Hamine  阅读(89)  评论(0编辑  收藏  举报