AtCoder Beginner Contest 368(A - D)

传送门

A - Cut

原题
在这里插入图片描述

限制
在这里插入图片描述

输入
在这里插入图片描述

输出
在这里插入图片描述

测试样例

input1
5 3
1 2 3 4 5
output1
3 4 5 1 2

最初,写在卡片上的整数从上到下为 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5

从牌堆底部取出三张牌放在上面后,写在牌上的整数从上到下变为 3 , 4 , 5 , 1 , 2 3,4,5,1,2 3,4,5,1,2

input2
6 2
1 2 1 2 1 2
output2
1 2 1 2 1 2

分析

  • 这题可以纯暴力,有个比较简单的方法是先把前 n − k n - k nk个元素翻转,再把后 k k k 个元素翻转,然后整体翻转即可,要注意边界。
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int n, k;
	std::cin >> n >> k;
	std::vector<int> a(n);
	for(int i = 0; i < n; i++) {
		std::cin >> a[i];
	}
	std::reverse(a.begin(), a.begin() + n - k);
	std::reverse(a.begin() + n - k, a.end());
	std::reverse(all(a));
	for(auto x : a) {
		std::cout << x << " ";
	}

	return 0;
}

B - Decrease 2 max elements

原题
在这里插入图片描述

限制
在这里插入图片描述

输入
在这里插入图片描述

输出
在这里插入图片描述

测试样例

input1
4
1 2 3 3
output1
4
在这里插入图片描述

input2
3
1 1 100
output2
2

分析

  • 这题同样可以纯暴力,赛时没有去想比较简单的方法
  • 每次操作之前进行排序,并对数组中仍为正整数的个数计数,只要个数 ≥ 2 \ge 2 2,那么就需要进行操作,每次把操作的次数 + 1 +1 +1即可
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int n;
	std::cin >> n;
	std::vector<int> a(n);
	for(int i = 0; i < n; i++) {
		std::cin >> a[i];
	}
	int cnt = n;
	int ans = 0;
	while(cnt >= 2) {
		std::sort(all(a), std::greater());
		a[0]--;
		a[1]--;
		if(a[0] <= 0) {
			cnt--;
		}
		if(a[1] <= 0) {
			cnt--;
		}
		ans++;
	}
	std::cout << ans;


	return 0;
}

C - Triple Attack

原题
在这里插入图片描述

限制
在这里插入图片描述

输入
在这里插入图片描述

输出
在这里插入图片描述

测试样例

input1
3
6 2 2
output1
8
在这里插入图片描述

input2
9
1 12 123 1234 12345 123456 1234567 12345678 123456789
output2
82304529

input3
5
1000000000 1000000000 1000000000 1000000000 1000000000
output3
3000000000

分析

  • 记答案为 a n s ans ans,操作次数与要减的数有个规律,当 a n s m o d 3 = = 0 ans _{mod 3} == 0 ansmod3==0时,此时进行的是 − 3 -3 3 操作,否则是 − 1 -1 1 操作
  • 假设当前要操作的数为 a i a_{i} ai,由于减数是每3个一循环,每个循环可以减去5,因此统计 a i a_{i} ai进行 − 5 -5 5的操作次数,然后再根据第 a n s ans ans次操作进行 − 1 -1 1 − 3 -3 3 操作
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int n;
	std::cin >> n;
	i64 ans = 0;
	for(int i = 0; i < n; i++) {
		int m;
		std::cin >> m;
		ans += m / 5 * 3;
		m %= 5;
		while(m > 0) {
			ans++;
			if(ans % 3 == 0) {
				m -= 3;
			} else {
				m--;
			}
		}
	}

	std::cout << ans;

	return 0;
}

D - Minimum Steiner Tree

原题
在这里插入图片描述

限制
在这里插入图片描述

输入
在这里插入图片描述

输出
在这里插入图片描述

测试样例

input1
7 3
1 2
1 3
2 4
2 5
3 6
3 7
1 3 5
output1
4在这里插入图片描述

input2
4 4
3 1
1 4
2 1
1 2 3 4
output2
4

input3
5 1
1 4
2 3
5 2
1 2
1
output3
1

分析

  • 由于题给的是一颗树,每个节点只有一个父亲节点,所以我们可以这样想,假设当前来到节点 a i a_{i} ai,只有当当前节点的上级节点当前节点的下级节点有需要加入新树的点,这个点才需要加入新树,因为只有这样这两个点才能连在一颗树上
  • 这种由下级节点影响上级节点的思路我们可以用树形dp来做
  • 0 0 0 号节点为根节点,数组 d p i dp_{i} dpi 表示以节点 i i i 为根节点时有多少个节点加入了新树,再用数组 v v v 标记需要加入新树的点
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

int main() {

    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    int n, k;
    std::cin >> n >> k;
    std::vector<std::vector<int>> adj(n);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        std::cin >> u >> v;
        u--;
        v--;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    std::vector<int> v(n);
    for(int i = 0; i < k; i++) {
    	int m;
    	std::cin >> m;
    	m--;
    	v[m] = 1;
    }

    std::vector<int> dp(n);
    int ans = 0;
    auto dfs = [&](auto self, int u, int fa) -> void {

    	dp[u] = v[u];
    	int c = 0;
    	if(v[u]) {
    		c = 2;
    	}
    	for(auto v : adj[u]) {
    		if(v == fa) {
    			continue;
    		}
    		self(self, v, u);
    		dp[u] += dp[v];
    		if(dp[v] > 0) {
    			c++;
    		}
    	}

    	if(dp[u] < k) {
    		c++;
    	}
    	if(c >= 2) {
    		ans++;
    	}

    };

    dfs(dfs, 0, -1);
    std::cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值