比赛链接:
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;
}