1988(958div2)
A. Split the Multiset
多集是一个数字集合,其中可以有相等的元素,数字的顺序并不重要。例如,
你有一个多集合
在一次操作中,可以选择
求使
我觉得无论怎样分,尽量分多一些就是最优了,所以每次都
void solve() {
int n, k;cin >> n >> k;
priority_queue<int>q;
q.push(n);
int ans = 0;
while (q.size()) {
int x = q.top();q.pop();
if (x == 1)break;
if (x > k) {
q.push(x - k + 1);
}
ans++;
}
cout << ans << '\n';
}
这个思路和我一样,相当于每次减少
void solve() {
int n, k;cin >> n >> k;
cout << (n + k - 3) / (k - 1) << "\n";
}
B. Make Majority
给您一个序列
这里,由
- 如果是
,多数为 。 - 如果是
,多数是 。
请判断能否用有限次的运算做出
先将多个 0 合并在一起(将 0 个数弄到最小)算最有可能得到
void solve() {
int n;cin >> n;
string s;cin >> s;
int cnt0 = 0, cnt1 = 0, ok = 0;
for (int i = 0;i < s.size();i++) {
if (s[i] == '1') {
cnt1++;ok = 0;
} else {
if (!ok) {
cnt0++;ok = 1;
}
}
}
if (cnt1 > cnt0) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
C. Increasing Sequence with Fixed OR
给你一个正整数
。 数组严格递增。
这个题目难度和 B 相同
只需要每个元素去掉一位为 1 的二进制位即可。所以方法个数是
坑点:
__builtin_popcount()
参数是unsigned int
,对于 long long 不适用- 当数据范围超 int 之后,都需要
1ll<<i
这样,养成习惯 - 需要特判一下只有一个二进制位是 1 的情况,因为去掉一位之后就是 0 了,而题目要求正整数。需要去掉
#define int long long
void solve() {
int n;cin >> n;
int k = 0;
vector<int>ans;
for (int i = __lg(n);i >= 0;i--) {
if ((n >> i) & 1) {
k++;
ans.push_back(n - (1ll << i));
}
}
if (k == 1) {
cout << "1\n" << n << "\n";
return;
}
cout << k + 1 << '\n';
for (auto x : ans)cout << x << " ";
cout << n << '\n';
}
D. The Omnipotent Monster Killer
你是怪物杀手,想要杀死一群怪物。这些怪物位于一棵有
在每个回合中,会依次发生以下情况:
- 所有活着的怪物攻击你。你的生命值会按照所有活体怪物攻击点的总和减少。
- 您选择一些(可能是全部,也可能是一个都没有)怪物并杀死它们。被杀死后,怪物将无法再进行任何攻击。
有一个限制条件:在一个回合内,您不能杀死由一条边直接相连的两只怪物。
如果您以最佳方式选择攻击的怪物,那么在所有回合后,受到的最小伤害是多少?
Solution
若这个题目只有一个回合,实际上就是 树的最大权值的独立集。即没有上司的舞会
树形 DP
#define int long long
void solve() {
int n;cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<vector<int>> g(n + 1);
for (int i = 1; i < n; i++) {
int u, v;cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
vector<array<int, 30>> dp(n + 1);
auto dfs = [&](auto self, int u, int fa = -1)->void {
for (int i = 1; i <= 25; i++) dp[u][i] = a[u] * i;
for (auto v : g[u]) {
if (v == fa) continue;
self(self, v, u);
for (int i = 1; i <= 25; i++) {
int mn = 9e18;
for (int j = 1; j <= 25; j++)
if (i != j) mn = min(mn, dp[v][j]);
dp[u][i] += mn;
}
}
};
dfs(dfs, 1);
int res = 9e18;
for (int i = 1; i <= 25; i++) res = min(res, dp[1][i]);
cout << res << '\n';
}
E. Range Minimum Sum
对于长度为
一个排列是长度为
- 从
中删除 ,连接剩余部分,得到 。 - 计算
。
待补,目前无计划...