把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

AtCoder Beginner Contest 368 题解&&思路(A-D,F)

AtCoder Beginner Contest 368 题解&&思路(A-D,F)

A - Cut

题目描述

\(N\) 个数在一个桶里面,从上往下第 \(i\) 个数是 \(A_i\),从桶下面取出 \(K\) 个数,保持原顺序放在桶的上面,从上到下打印写在卡片上的整数。

思路

时间复杂度 \(\mathcal{O}(N).\)

本质上就是先输出后 \(K\) 个数然后再从前面输出。

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#define N 105

using namespace std;
int a[N];
signed main(){
	int n,k;
	cin >> n >> k;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	for (int i = n - k + 1;i <= n;i ++) cout << a[i] << ' ';
	for (int i = 1;i < n - k + 1;i ++) cout << a[i] << ' ';
	return 0;
}

B - Decrease 2 max elements

题目描述

问题陈述

给你一个由 \(N\) 个正整数 \(A = (A_1, A_2, \dots ,A_N)\) 组成的序列。高桥重复下面的操作,直到 \(A\) 包含一个或更少的正整数元素:

  • 按降序排列 \(A\) 。然后将 \(A_1\)\(A_2\) 减少 \(1\)

求他执行此操作的次数。

思路

直接模拟即可。

用数组或者 \(map\) 存一下大于 \(0\) 的有多少个就行,每次操作后更新。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stdlib.h>
#include <map>
#define N 105
using namespace std;
int n,a[N],ans;
map<bool,int> mp; 
signed main(){
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	for (int i = 1;i <= n;i ++) {
		if (a[i] > 0) mp[1] ++;
		else mp[0] ++;
	}
	while(mp[1] > 1) {
		stable_sort(a + 1,a + 1 + n,[](int x,int y) {
			return x > y;
		});
		a[1] --,a[2] --;
		if (a[1] == 0) mp[1]--,mp[0] ++;
		if (a[2] == 0) mp[1]--,mp[0] ++;
		ans ++;
	}
	cout << ans;
	return 0;
}

C - Triple Attack

题目描述

问题陈述

你正在玩一个游戏。

\(N\) 个敌人排成一排,最前面的 \(i\) 个敌人的生命值是 \(H_i\)

你将使用初始化为 \(0\) 的变量 \(T\) 重复以下操作,直到所有敌人的生命值都变为 \(0\) 或更少。

  • \(T\) 增加 \(1\) 。然后,攻击最前方生命值为 \(1\) 或更高的敌人。如果 \(T\)\(3\) 的倍数,敌人的生命值会减少 \(3\) ;否则,生命值会减少 \(1\)

当所有敌人的生命值变为 \(0\) 或更少时,求 \(T\) 的值。

思路

赛时有细节问题,没打出来,呜呜呜呜

我们可以发现一个循环节:

\[T=3,4,5 \]

这里攻击对方是 \(5\) 的健康值,而只用迭代 \(3\)\(T.\)

对于没有到 \(T\%3=0\) 的,暴力枚举即可(我赛时就是因为没有这样,想用 \(O(1)\) 解决,导致有一大堆细节问题……)。

其他的就不必多说了。

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
#define N 200005
#define int long long
using namespace std;
int n,a[N],T = 0;
signed main(){
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	for (int i = 1;i <= n;i ++) {
		while(a[i] > 0 && T % 3) {
			T ++;
			if (T % 3) a[i]--;
			else a[i] -= 3;
		}
		if (a[i] > 0) {
			int m = a[i] / 5;
			T += m * 3;
			a[i] %= 5;
			if (a[i] >= 1) T ++;
			if (a[i] >= 2) T ++;
			if (a[i] >= 3) T ++;
		}
	}
	cout << T;
	return 0;
}

D - Minimum Steiner Tree

题目描述

问题陈述

给你一棵树,树上有 \(N\) 个顶点,编号为 \(1\)\(N\) 。第 \(i\) 条边连接顶点 \(A_i\)\(B_i\)

考虑从这个图中删除一些边和顶点(可能为零)后可以得到一棵树。求这样一棵树中包含所有 \(K\) 指定顶点 \(V_1,\ldots,V_K\) 的顶点的最小数目。

思路

注意到题目给的是一棵树,也就是说从 \(u\)\(v\) 有且仅有一条路径,难道这里我们要枚举 \(V_i,V_j\) ?其实不用,我们可以从 \(V_1\) 为根开始 dfs 图的遍历,碰到节点 \(x\in V\) 的,就更新这条路径上的点(表示算作答案),但一定要先遍历再更新(有可能当前节点 \(u\in V\)\(x\in V\)\(x\)\(u\) 子树下的一个点,这样就会顺便把 \(V_1\rightarrow u\) 的路径也给更新了)。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <stdlib.h>
#include <vector>
#include <set>
#define N 200005

using namespace std;
int n,v[N],k;
vector<int> g[N];
bool bj[N];
bool vis[N];
int stk[N],tp;
void dfs(int cur,int fa) {
	tp ++,stk[tp] = cur;
	for (auto i : g[cur])
		if (i != fa){
			dfs(i,cur);
			if (bj[i] && !vis[i]) {
				for (int j = 1;j <= tp;j ++) vis[stk[j]] = 1;
				vis[i] = 1;
			}
		}
	tp --;
}
signed main(){
	cin >> n >> k;
	for (int i = 1;i < n;i ++) {
		int u,v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for (int i = 1;i <= k;i ++) cin >> v[i],bj[v[i]] = 1;
	dfs(v[1],0);
	vis[v[1]] = 1;
	int ans = 0;
	for (int i = 1;i <= n;i ++) ans += vis[i];
	cout << ans;
	return 0;
}

E - Train Delay

题目描述

问题陈述

在 Atcoder 国家,有 \(N\) 座城市,编号为 \(1\)\(N\) ,以及 \(M\) 列火车,编号为 \(1\)\(M\)\(i\) 次列车在 \(S_i\) 点从城市 \(A_i\) 出发,在 \(T_i\) 点到达城市 \(B_i\)

给定一个正整数 \(X_1\) ,求一个非负整数 \(X_2,\ldots,X_M\) 的最小值 \(X_2+\ldots+X_M\) ,以满足下列条件。

  • 条件对于所有满足 \(1 \leq i,j \leq M\) 的一对 \((i,j)\) ,如果 \(B_i=A_j\)\(T_i \leq S_j\) ,那么 \(T_i+X_i \leq S_j+X_j\)
    • 换句话说,对于任何一对原本可以换乘的列车,即使将每趟列车 \(i\) 的出发和到达时间延迟 \(X_i\) ,仍然可以换乘。

可以证明,这种将 \(X_2,\ldots,X_M\) 设置为 \(X_2+\ldots+X_M\) 的最小值的方法是唯一的。

思路

赛场上没有想出来就先做 \(T_6\) 了,后面更。

F - Dividing Game

题目描述

问题陈述

给你一个由 \(N\) 个正整数 \(A = (A_1, A_2, \dots ,A_N)\) 组成的序列,其中每个元素至少是 \(2\) 。安娜和布鲁诺用这些整数玩一个游戏。他们轮流执行以下操作,安娜先执行。

  • 自由选择一个整数 \(i \ (1 \leq i \leq N)\) 。然后,自由选择 \(A_i\) 的一个不是 \(A_i\) 本身的正整除 \(x\) ,并将 \(A_i\) 替换为 \(x\)

不能进行操作的一方输,另一方赢。假设两位棋手都以最佳的方式下棋,那么谁会赢呢?

思路

这是道博弈论的题目,不难想出来这题应该和因数有关,考虑时间复杂度 \(\mathcal{O}(N\sqrt N)\) 的算法。

看到此题我先求出其因数的个数(除了它本身),然后,观察到现在是不是跟之前做过的题目一样,没错是它!

——Nim 游戏

但交上去,挂了……

现在我考虑这条关于 \(A_i\) 的因子链,发现跟它的最长链有关,不过也很好理解,拿最长能够使先手必胜的状态更大,于是就 \(A\) 了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 100005
using namespace std;
int n,a[N],cnt;
signed main(){
	cin >> n;
	for (int i = 1;i <= n;i ++) {
		cin >> a[i];
		int p = 0;
		for (int j = 2;j * j <= a[i];j ++)
			while(a[i] % j == 0) a[i] /= j,p ++;
		if (a[i] > 1) p ++;
		cnt ^= p;
//		cout << p << endl;
	}
	if (cnt == 0) return cout << "Bruno",0;
	cout << "Anna"; 
	return 0;
}
posted @ 2024-10-30 12:50  high_skyy  阅读(38)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end