🔵
【ABC352】AtCoder Beginner Contest 352【C++】
コンテスト名
AtCoder Beginner Contest 352
コンテストURL
開催日
2024/05/04 21:00-22:40
A: AtCoder Line
解法
- 駅
が駅Z と駅X の間にあるかを判別するY
ABC352A.cpp
#include <iostream>
using namespace std;
int main(){
int n, x, y, z;
cin >> n >> x >> y >> z;
if(x>y && x>z && z>y){
cout << "Yes" << endl;
}else if(x<y && x<z && z<y){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
return 0;
}
B: Typing
解法
- 前から順番に比較する
ABC352B.cpp
#include <iostream>
#include <string>
using namespace std;
int main(){
string s, t;
cin >> s >> t;
int j = 0;
for(int i=0; i<s.size(); i++){
while(s[i]!=t[j]){
j++;
}
if(i){
cout << " ";
}
cout << j+1;
j++;
}
cout << endl;
return 0;
}
C: Standing On The Shoulders
解法
- どの巨人が一番上に立つと高さが最大になるかについて
の全探索をするO(N) - 一番上に立つ巨人以外は肩の高さ
分だけ貢献するA_i - 一番上に立つ巨人は頭の高さ
分だけ貢献するB_i -
の総和を求めてA_i の最大値を足すB_i - A_i - 「巨人の肩の上に立つ」
ABC352C.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
vector<int> A(n), B(n);
for(int i=0; i<n; i++){
cin >> A[i] >> B[i];
}
long long int sum = 0;
for(int i=0; i<n; i++){
sum += A[i];
}
long long int maxv = 0;
for(int i=0; i<n; i++){
maxv = max(maxv, sum-A[i]+B[i]);
}
cout << maxv << endl;
return 0;
}
D: Permutation Subsequence
解法
- どの連続する
個の数列を採用するかを全探索するK - 連続する
個の数列はK 通りN - K + 1
- 連続する
- 数列が昇順になるように添字列を並び替える
-
set<int>
を用いて添字の最大値と最小値を更新する-
erase()
とinsert()
で更新する- 計算量はともに
O(\log N)
- 計算量はともに
- 最大値は
*.rbegin()
、最小値は*.begin()
によって で取得できるO(1)
-
- 最大値と最小値の差
の最小値を求めるi_K - i_1
ABC352D.cpp
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main(){
int n, k;
cin >> n >> k;
vector<int> P(n);
int p;
for(int i=0; i<n; i++){
cin >> p;
p--;
P[p] = i;
}
set<int> S;
for(int i=0; i<k; i++){
S.insert(P[i]);
}
int ans = *S.rbegin() - *S.begin();
for(int i=k; i<n; i++){
S.erase(P[i-k]);
S.insert(P[i]);
ans = min(ans, *S.rbegin() - *S.begin());
}
cout << ans << endl;
return 0;
}
E: Clique Connect
解法
- クラスカル法で最小全域木を求める
- 部分集合
のすべての頂点間に重みS_i = \lbrace A_{i, 1}, A_{i, 2},..., A_{i, K_i}, \rbrace の辺を追加することは、すべてのC_i 間だけに重みA_{i, j}, A_{i, j+1} の辺を追加することと同じC_i - 辺の数を
本から\frac{K_i (K_i - 1)}{2} 本に省略できるK_i - 1
- 辺の数を
- クラスカル法において、すでにすべての頂点が連結であるならばそれ以上は辺が追加されないという性質を利用する
ABC352E.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;
struct UnionFind{
vector<int> P;
vector<int> S;
UnionFind(int n) : P(n), S(n, 1){
for(int i=0; i<n; i++){
P[i] = i;
}
}
int find(int x){
if(x==P[x]){
return x;
}
return P[x] = find(P[x]);
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if(x==y){
return;
}
if(S[x]<S[y]){
swap(x, y);
}
P[y] = x;
S[x] += S[y];
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return S[find(x)];
}
};
int main(){
int n, m;
cin >> n >> m;
vector<tuple<int, int, int>> V;
int k, c;
for(int i=0; i<m; i++){
cin >> k >> c;
int pre, a;
for(int j=0; j<k; j++){
cin >> a;
a--;
if(j){
V.emplace_back(c, pre, a);
}
pre = a;
}
}
sort(V.begin(), V.end());
UnionFind uf(n);
long long int sum = 0;
for(int i=0; i<V.size(); i++){
auto [c, a, b] = V[i];
if(!uf.same(a, b)){
sum += c;
uf.unite(a, b);
}
}
if(uf.size(0)!=n){
cout << -1 << endl;
}else{
cout << sum << endl;
}
return 0;
}
Discussion