AtCoder Beginner Contest 352
Time : 2024-05-04(Sat) 20:00 - 2024-05-04(Sat) 21:40
A AtCoder Line
問題陳述
輸入
輸入內容由標準輸入法提供,格式如下
N X Y Z
題解
題意為檢查Z是否處於X與Y之間
需根據X與Y的大小來判斷乘坐進站列車還是出站列車
void solve() {
cin >> n >> x >> y >> z;
if(x > y)swap(x, y);
cout << (x <= z && z <= y ? "Yes" : "No") << endl;
}
B Typing
問題陳述
題解
S為理想輸入, T為實際輸入
題意為在T與S的字串匹配, 每次輸入S在T中的下標
演算法 : 雙指標
void solve() {
string s, t;
cin >> s >> t;
for(int i = 0, j = 0; i < t.size() ; i++) {
if(s[j] == t[i])cout << i + 1 << " ", j++;
}
}
C Standing On The Shoulders
問題陳述
題解
總高度為N個巨人的肩高和加上最上方巨人的頭高-肩高
總高度最大即最上方巨人頭肩高差最大
遍歷得最大值即可, 記得開long long
void solve() {
cin >> n;
int sd, hd, mx = -1;
for(int i = 0; i < n; i++) {
cin >> sd >> hd;
res += sd;
mx = max(mx, hd - sd);
}
cout << res + mx << endl;
}
D
問題陳述
題解
題意有點繞人, 簡單來說是在 1 ~ N 的排列中找到長度為 k 的下標集合, 使得該下標集合對應的排列集合排序後為k長度的連續序列(a , a + 1 , a + 2 ... a + k - 1), 找到滿足該條件下標集合的極差的最小值
一開始半天沒讀明白題, 覺得答案有單調性決定用二分答案加上滑動視窗來做, 思路不會最佳化TLE了
看到jiangly大佬有一個很巧妙的做法, 下標和排列P都是1 ~ N, 可以使用陣列一一對應儲存
使用set維護一個 k 長度的滑動視窗, 遍歷 a 來尋找最小值, 具體見程式碼註釋
void solve() {
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> t;
p[t] = i; //儲存下標
}
set<int> s;//set集合有序儲存滑動視窗中的下標
for(int i = 1; i <= n; i++) { //列舉整數a
s.insert(p[i]);
if(i > k)s.erase(p[i - k]); //滑動視窗
if(i >= k)
ans = min(ans, *s.rbegin() - *s.begin()); //維護最大下標
}
cout << ans;
}
E Clique Connect
問題陳述
題解
很裸的一道求最小生成樹題
稠密圖, 選用Kruskal演算法來完成
題目給定邊的時候, 由於邊權相等, 可以把給定集合看作一整個連通塊, 便只相當於插入了k-1條邊
int n, m, k, c, a, root, cnt;
int ans;
int p[N];//並查集維護節點的父節點
struct E {
int a, b, c;
bool operator < (const E& C) {
return c < C.c;
}
} edgs[N * 2];
int find(int u) {
if(u != p[u])p[u] = find(p[u]);
return p[u];
}
int kruskal() {
for(int i = 1; i <= n; i++)p[i] = i;//初始化
int num = 0;//儲存最小生成樹邊的數目
sort(edgs, edgs + cnt);
for(int i = 0; i < cnt; i++) { //列舉edgs
int a = edgs[i].a, b = edgs[i].b, c = edgs[i].c;
if(find(a) != find(b)) { //如果兩個節點沒有聯通(所在連通塊根節點不同)
p[find(a)] = find(b);
ans += c;
num++;
}
}
return num;
}
void solve() {
cin >> n >> m;
while(m--) {
cin >> k >> c;//題意即給定含有k個節點的連通塊
for(int i = 0; i < k; i++) {
cin >> a;
if(i > 0)
edgs[cnt ++ ] = {root, a, c};//cnt為邊的數量
root = a;//以第一個節點為該連通塊根節點
}
}
if(kruskal() == n - 1)
cout << ans << endl;
else
cout << -1 << endl;
}
F,G 等待更新...