AtCoder Beginner Contest 240 題解
- A - Edge Checker
- B - Count Distinct Integers
- C - Jumping Takahashi
- D - Strange Balls
- E - Ranges on Tree
- F - Sum Sum Max
A - Edge Checker
題目大意:
給個1 - 10 數字圍成一個圈,給你兩個數問你是否相鄰
int main (){ IOS int a, b; cin >> a >> b; if (abs (a - b) == 1){ cout << "Yes" << endl; } else if (a == 10 && b == 1 || a == 1 && b == 10) { cout << "Yes" << endl; } else cout << "No" << endl; }
B - Count Distinct Integers
題目大意;
給一個數組,問你出現了多少不同的數字。(丟 set 裡就行)
int main (){
IOS
set <int> s;
int n; cin >> n;
for (int i = 1 ; i <= n ; i ++){
int x; cin >> x;
s.insert(x);
}
cout << s.size () << endl;
return 0;
}
C - Jumping Takahashi
題目大意:
給定目的點 x, 跳躍 n 次,每次可以從 a, b 中選擇一個數跳躍一定的距離。問從起點 0 開始,能否恰好跳躍到 x 點。
分析:
暴力列舉每一次選 a 或者 b, 時間複雜度 \(O (2^n)\) , 顯然不行。考慮用 \(dp[i][j]\)去表示前 i 次跳躍後,是否能到達 j 點。
時間複雜度 \(O (nx)\) ,可以用滾動優化掉一維,但是懶得搞了qwq。
int f[105][10005]; int main (){ IOS int n, x; cin >> n >> x; f[0][0] = 1; for (int i = 1 ; i <= n ; i ++){ int a, b; cin >> a >> b; for (int j = 0 ; j <= 10000 - a ; j ++){ if (f[i - 1][j]) f[i][j + a] = f[i - 1][j]; } for (int j = 0 ; j <= 10000 - b ; j ++){ if (f[i - 1][j]) f[i][j + b] = f[i - 1][j]; } } if (f[n][x]){ cout << "Yes" << endl; } else cout << "No" << endl; return 0; }
D - Strange Balls
題目大意:
類似於 “祖瑪” 的遊戲,一個一個往桶裡新增小球,當 小球的編號與連續個數相同時,這部分小球會被消掉。求出每次新增小球后桶中小球個數。
分析:
用兩個棧去維護即可,一個棧維護個數,一個棧維護桶內小球的情況,然後模擬輸出即可。(一開始以為連續球必然會消去,wa了一發)
#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
using namespace std;
const int N=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;
int a[N];
int main (){
IOS
int t; cin >> t;
stack <int> s, c;
int now = 0, cnt = 0;
while (t --){
int n; cin >> n;
if (s.empty()){
s.push(n);
now = n; cnt ++;
}
else {
if (s.top () == n){
if (cnt == n - 1){
while (s.size () > 0 && s.top () == n) s.pop();
if (s.empty()) now = 0, cnt = 0;
else{
if (c.empty()) cnt = 0;
else {
cnt = c.top(); c.pop();
}
n = s.top ();
}
}
else {
s.push(n);
cnt ++;
}
}
else {
s.push(n);
c.push(cnt);
now = n, cnt = 1;
}
}
cout << s.size () << endl;
}
return 0;
}
E - Ranges on Tree
題目大意:
給一顆根節點為 1 的樹,每個節點有一個集合 \(S_i\) , 表示以該節點為根節點的子樹包含的節點數。要求給樹上的所有節點,分配一個區間,使得節點之間的區間關係和 \(S_i\) 之間的關係一致。輸出分配情況,同時使得所有區間的最右端最小。(用盡可能小的數去分配)
例如: 如果節點2 和節點 3 的子樹沒有交集,那麼為這兩個節點分配的區間的交集也應當為空集。如果節點 1 的子樹包含節點 2 的子樹,那麼區間 1 也應當包含 區間 2。
分析:
顯然可以看出,根節點 1 包含所有其他節點, 那麼根節點的區間一定是最大的。又可以看出,每個葉子節點一定是相互獨立的,所以要為每個葉子節點分配一個值。所以,根節點的長度為樹中葉子節點的個數。按每顆子樹的葉子節點數分配區間即可。
題目不難想,題意有點難讀,我讀了n個錯誤題意 ,比賽中實現得比較複雜,第一遍 dfs 求 每棵樹的葉子節點個數,第二遍 dfs 賦值。
#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define Equ(a,b) (fabs((a)-(b))<eps)
#define More(a,b) (((a)-(b))>(eps))
#define x first
#define y second
using namespace std;
const int N=3e5+7;
const double eps=1e-6;
const int mod=1e9+7;
vector <int> a[N];
int cnt = 0;
bool st[N];
int d[N];
struct node{
int l, r;
};
node ans[N];
int dfs (int u){
bool flag = 0;
for (auto i : a[u]){
if (!st[i]){
flag = 1;
st[i] = 1;
d[u] += dfs(i);
st[i] = 0;
}
}
if (flag)
return d[u];
d[u] = 1;
return d[u];
}
void dfs2 (int u, int l){
int loc = l;
ans[u].l = l, ans[u].r = l + d[u] - 1;
for (auto i : a[u]){
if (!st[i]){
st[i] = 1;
dfs2 (i, loc);
loc += d[i];
st[i] = 0;
}
}
}
int main (){
IOS
int n; cin >> n;
for (int i = 1 ; i < n ; i ++){
int u, v; cin >> u >> v;
a[u].push_back(v);
a[v].push_back(u);
}
st[1] = 1;
dfs(1);
memset (st, 0, sizeof st);
st[1] = 1;
dfs2 (1, 1);
for (int i = 1 ; i <= n ; i ++){
cout << ans[i].l << ' ' << ans[i].r << endl;
}
return 0;
}