本文主要是介绍AtCoder Beginner Contest 368 题解思路(A-D,F),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
AtCoder Beginner Contest 368 题解&&思路(A-D,F)
A - Cut
题目描述
有 N N N 个数在一个桶里面,从上往下第 i i i 个数是 A i A_i Ai,从桶下面取出 K K K 个数,保持原顺序放在桶的上面,从上到下打印写在卡片上的整数。
思路
时间复杂度 O ( N ) . \mathcal{O}(N). O(N).
本质上就是先输出后 K K K 个数然后再从前面输出。
#include <iostream>
#include <cstdio>
#include <stdlib.h>
#define N 105using 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 N N 个正整数 A = ( A 1 , A 2 , … , A N ) A = (A_1, A_2, \dots ,A_N) A=(A1,A2,…,AN) 组成的序列。高桥重复下面的操作,直到 A A A 包含一个或更少的正整数元素:
- 按降序排列 A A A 。然后将 A 1 A_1 A1 和 A 2 A_2 A2 减少 1 1 1 。
求他执行此操作的次数。
思路
直接模拟即可。
用数组或者 m a p map map 存一下大于 0 0 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 N N 个敌人排成一排,最前面的 i i i 个敌人的生命值是 H i H_i Hi 。
你将使用初始化为 0 0 0 的变量 T T T 重复以下操作,直到所有敌人的生命值都变为 0 0 0 或更少。
- 将 T T T 增加 1 1 1 。然后,攻击最前方生命值为 1 1 1 或更高的敌人。如果 T T T 是 3 3 3 的倍数,敌人的生命值会减少 3 3 3 ;否则,生命值会减少 1 1 1 。
当所有敌人的生命值变为 0 0 0 或更少时,求 T T T 的值。
思路
赛时有细节问题,没打出来,呜呜呜呜
我们可以发现一个循环节:
T = 3 , 4 , 5 T=3,4,5 T=3,4,5
这里攻击对方是 5 5 5 的健康值,而只用迭代 3 3 3 次 T . T. T.
对于没有到 T % 3 = 0 T\%3=0 T%3=0 的,暴力枚举即可(我赛时就是因为没有这样,想用 O ( 1 ) O(1) 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 N N 个顶点,编号为 1 1 1 至 N N N 。第 i i i 条边连接顶点 A i A_i Ai 和 B i B_i Bi 。
考虑从这个图中删除一些边和顶点(可能为零)后可以得到一棵树。求这样一棵树中包含所有 K K K 指定顶点 V 1 , … , V K V_1,\ldots,V_K V1,…,VK 的顶点的最小数目。
思路
注意到题目给的是一棵树,也就是说从 u u u 到 v v v 有且仅有一条路径,难道这里我们要枚举 V i , V j V_i,V_j Vi,Vj ?其实不用,我们可以从 V 1 V_1 V1 为根开始 dfs
图的遍历,碰到节点 x ∈ V x\in V x∈V 的,就更新这条路径上的点(表示算作答案),但一定要先遍历再更新(有可能当前节点 u ∈ V u\in V u∈V 而 x ∈ V x\in V x∈V 且 x x x 是 u u u 子树下的一个点,这样就会顺便把 V 1 → u V_1\rightarrow u V1→u 的路径也给更新了)。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <stdlib.h>
#include <vector>
#include <set>
#define N 200005using 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 N N 座城市,编号为 1 1 1 至 N N N ,以及 M M M 列火车,编号为 1 1 1 至 M M M 。 i i i 次列车在 S i S_i Si 点从城市 A i A_i Ai 出发,在 T i T_i Ti 点到达城市 B i B_i Bi 。
给定一个正整数 X 1 X_1 X1 ,求一个非负整数 X 2 , … , X M X_2,\ldots,X_M X2,…,XM 的最小值 X 2 + … + X M X_2+\ldots+X_M X2+…+XM ,以满足下列条件。
- 条件对于所有满足 1 ≤ i , j ≤ M 1 \leq i,j \leq M 1≤i,j≤M 的一对 ( i , j ) (i,j) (i,j) ,如果 B i = A j B_i=A_j Bi=Aj 和 T i ≤ S j T_i \leq S_j Ti≤Sj ,那么 T i + X i ≤ S j + X j T_i+X_i \leq S_j+X_j Ti+Xi≤Sj+Xj 。
- 换句话说,对于任何一对原本可以换乘的列车,即使将每趟列车 i i i 的出发和到达时间延迟 X i X_i Xi ,仍然可以换乘。
可以证明,这种将 X 2 , … , X M X_2,\ldots,X_M X2,…,XM 设置为 X 2 + … + X M X_2+\ldots+X_M X2+…+XM 的最小值的方法是唯一的。
思路
赛场上没有想出来就先做 T 6 T_6 T6 了,后面更。
F - Dividing Game
题目描述
问题陈述
给你一个由 N N N 个正整数 A = ( A 1 , A 2 , … , A N ) A = (A_1, A_2, \dots ,A_N) A=(A1,A2,…,AN) 组成的序列,其中每个元素至少是 2 2 2 。安娜和布鲁诺用这些整数玩一个游戏。他们轮流执行以下操作,安娜先执行。
- 自由选择一个整数 i ( 1 ≤ i ≤ N ) i \ (1 \leq i \leq N) i (1≤i≤N) 。然后,自由选择 A i A_i Ai 的一个不是 A i A_i Ai 本身的正整除 x x x ,并将 A i A_i Ai 替换为 x x x 。
不能进行操作的一方输,另一方赢。假设两位棋手都以最佳的方式下棋,那么谁会赢呢?
思路
这是道博弈论的题目,不难想出来这题应该和因数有关,考虑时间复杂度 O ( N N ) \mathcal{O}(N\sqrt N) O(NN) 的算法。
看到此题我先求出其因数的个数(除了它本身),然后,观察到现在是不是跟之前做过的题目一样,没错是它!
——Nim 游戏
但交上去,挂了……
现在我考虑这条关于 A i A_i Ai 的因子链,发现跟它的最长链有关,不过也很好理解,拿最长能够使先手必胜的状态更大,于是就 A A 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;
}
这篇关于AtCoder Beginner Contest 368 题解思路(A-D,F)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!