竞赛链接:Dashboard - Codeforces Round 958 (Div. 2) - Codeforces
ProblemA
题目链接:Problem - A - Codeforces
简单题解加代码:
Python:
def II():
return int(input())
def MII():
return map(int, input().split())
'''
模拟方法
'''
def func_1(n: int, k: int) -> int:
res = 0
cur = 1
while cur < n:
res += 1
cur += k - 1
return res
'''
数学方法
'''
def func_2(n: int, k: int) -> int:
return (n - 1 + k - 2) // (k - 1)
def main():
t = II()
res = []
'''
操作:是说给一个整数n,可以把n分成最多k项,每项相加的值为n,
此时操作次数加一
分成的k项每项也可以进行相同的操作,
结果:把n分成n个1
要求:求达到结果的最小操作次数
'''
for _ in range(t):
n, k = MII()
res.append(func_2(n, k))
for r in res:
print(r)
if __name__ == "__main__":
main()
C++:
#include <iostream>
#include <vector>
using namespace std;
//模拟方法
int func_1(int n, int k){
int res = 0;
int cur = 1;
while (cur < n){
res++;
cur += k - 1;
}
return res;
}
//数学方法
int func_2(int n, int k){
return (n - 1 + k - 2) / (k - 1);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
/*
操作:是说给一个整数n,可以把n分成最多k项,每项相加的值为n,
此时操作次数加一
分成的k项每项也可以进行相同的操作,
结果:把n分成n个1
要求:求达到结果的最小操作次数
*/
while(t--){
int n, k;
cin >> n >> k;
cout << func_2(n, k) << '\n';
}
return 0;
}
ProblemB
题目链接:Problem - B - Codeforces
简单题解加代码:
Python:
def II():
return int(input())
def MII():
return map(int, input().split())
def I():
return input()
#把连续的0全部变成一个0,最后比较0和1的次数即可
#需要注意多数的边界条件
def func(s: str) -> str:
#标记量
x = 1
cnt_0 = 0
cnt_1 = 0
for i in range(len(s)):
c = s[i]
if c == '1':
cnt_1 += 1
x = 1
if c == '0' and x == 1:
cnt_0 += 1
x = 0
return "YES" if cnt_0 < cnt_1 else "NO"
def main():
t = II()
res = []
'''
操作:对于一个二进制数组,选择一段,对于这一段的所有数字变成这一段的(多数)
多数概念:零的次数小于1多数就是1,否则为0
结果:把数组变成[1],也就是只含一个数字1的数组
要求:是否可以通过若干操作变成结果
'''
for _ in range(t):
n = II()
s = I()
res.append(func(s))
for r in res:
print(r)
if __name__ == "__main__":
main()
C++:
#include <iostream>
#include <vector>
using namespace std;
//把连续的0全部变成一个0,最后比较0和1的次数即可
//需要注意多数的边界条件
string func(string s){
//标记量,连续的0就只用加一次
int x = 1;
int cnt0 = 0;
int cnt1 = 0;
for (auto c : s){
if (c == '1'){
cnt1 += 1;
x = 1;
}
if (c == '0' && x == 1){
cnt0 += 1;
x = 0;
}
}
if (cnt0 < cnt1){
return "YES";
}else{
return "NO";
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
/*
操作:是说给一个整数n,可以把n分成最多k项,每项相加的值为n,
此时操作次数加一
分成的k项每项也可以进行相同的操作,
结果:把n分成n个1
要求:求达到结果的最小操作次数
*/
while(t--){
string s;
int n;
cin >> n;
cin >> s;
cout << func(s) << '\n';
}
return 0;
}
ProblemC
题目链接:Problem - C - Codeforces
简单题解加代码:
Python:
def II():
return int(input())
def MII():
return map(int, input().split())
def I():
return input()
'''
输入:整数n
目标:最长的数组a,数组a每一位都小于n,严格递增,
相邻两位按位或操作结果为n
输出:数组a长度
数组a元素
'''
'''
1.我们从最高位开始,找出n的二进制表示中所有为1的位。
2.对于每个为1的位,我们将其对应的值从n中减去,得到一个小于n的数。
这样可以保证相邻两个数按位或的结果为n
'''
def func(n: int) -> list[int]:
res = []
x = 1
while x <= n:
x <<= 1
while x:
x >>= 1
if (x & n != 0) and (x != n):
res.append(n - x)
res.append(n)
return res
def main():
t = II()
result = []
for _ in range(t):
n = II()
arr = func(n)
result.append(arr)
for res in result:
print(len(res))
#打印列表中所有元素用空格分割
print(*res)
if __name__ == "__main__":
main()
C++:
#include <iostream>
#include <vector>
using namespace std;
/*
输入:整数n
目标:最长的数组a,数组a每一位都小于n,严格递增,
相邻两位按位或操作结果为n
输出:数组a长度
数组a元素
*/
/*
1.我们从最高位开始,找出n的二进制表示中所有为1的位。
2.对于每个为1的位,我们将其对应的值从n中减去,得到一个小于n的数。
这样可以保证相邻两个数按位或的结果为n
*/
//注意题目范围,C++里面要用long long
vector<long long> func(long long n) {
vector<long long> res;
long long x = 1;
while (x <= n) {
x <<= 1;
}
while (x) {
x >>= 1;
if ((x & n) && (x != n)) {
res.push_back(n - x);
}
}
res.push_back(n);
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) {
long long n;
cin >> n;
vector<long long> res = func(n);
cout << res.size() << '\n';
for (int i = 0; i < res.size(); ++i) {
if (i > 0) cout << ' ';
cout << res[i];
}
cout << '\n';
}
return 0;
}
ProblemD
题目链接:Problem - D - Codeforces
简单题解加代码:
C++:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <limits>
using namespace std;
#define N 300000
#define B 20
long long a[N + 50];//怪兽攻击力
long long f[N + 50][B + 3];//树中连接节点的边
basic_string<int> v[N + 50];//用于构建树的邻接表
void dfs(int x, int fa){
long long pl[B + 3], pr[B + 3];
//计算当前节点生命值损失
for (int i = 1; i <= B; i++){
f[x][i] = a[x] * i;
}
//遍历当前节点的子节点
for (auto y : v[x]){
if (y != fa){
dfs(y, x);
// 处理左右子树的最小值
pl[0] = pr[B + 1] = 1e18;
// 计算左子树每一轮被击杀的最小值
for (int i = 1; i <= B; i++) {
pl[i] = pr[i] = f[y][i];
}
// 计算左子树每一轮被击杀的最小值
for (int i = 1; i <= B; i++) {
pl[i] = min(pl[i], pl[i - 1]);
}
// 计算右子树每一轮被击杀的最小值
for (int i = B; i >= 1; i--) {
pr[i] = min(pr[i], pr[i + 1]);
}
// 更新当前节点的损失值,选择左右子树最小的额外损失
for (int i = 1; i <= B; i++) {
f[x][i] += min(pl[i - 1], pr[i + 1]);
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
/*
输入:怪物数量
每个怪物的攻击力
节点连接情况
条件:每一轮会受到所有存活怪物的攻击,攻击后,
可以选择在树结构中不直接相连的怪物
死去的怪物下一回合不会攻击
目标:生命值减少的最小值
*/
while (t--){
long long n;
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
long long j,k;
for (int i = 1; i < n; i++){
cin >> j >> k;
v[j] += k;
v[k] += j;
}
dfs(1, 0);
long long res = 1e18;
for (int i = 1; i <= B; i++){
res = min(res, f[1][i]);
}
cout << res << '\n';
//清空邻接表
for (int i = 1; i <= n; i++){
v[i] = {};
}
}
}