B - 3^A
3进制,总是贪心使用高位,使得使用的数目最小
void solve() {
vector<int> b(20);
b[0] = 1;
for (int i = 1; i <= 10; i ++ ) b[i] = b[i - 1] * 3;
int m;
cin >> m;
vector<int> ans;
for (int j = 10; j >= 0; j -- )
if (b[j] <= m){
int t = m / b[j];
m -= t * b[j];
while (t -- ) ans.push_back(j);
}
cout << ans.size() << '\n';
for (auto x : ans)
cout << x << ' ';
}
D - Buildings
熟练使用数据结构栈Stack
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> a(n + 1), ans(n + 1);
stack<int> st;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = n; i >= 1; i -- ){
int x = a[i];
while (!st.empty() && x > st.top()) st.pop();
st.push(x);
ans[i - 1] = st.size();
}
for (int i = 1; i <= n; i ++ ){
cout << ans[i] << ' ';
}
}
E - K-th Largest Connected Components
联系通路,并查集
合并并查集时需要合并2个并查集内的顶点,显然Set求有序。
如果记录全部的点,一次会最多记录 $n*(n+1)/2$ 个顶点,合并 $n$ 次显然会超时。
注意到 $MAX-K$ 为10,所以第 $k-th$ 大只与前 $MAX-K$ 有关。所以只合并时,只记录前 $MAX-K$ 大即可。
(寻找2个集合的前 $MAX_K$ 大或与会十分麻烦,不如分别将2的集合内的前 $MAX_K$ 大合并。因为大集合的前 $MAX_K$ 大只与 2的小集合各自的前 $MAX_K$ 大有关.)
时间复杂度为 $O(MKlog{2K})$
const int N = 2e5 + 10;
int n, m;
set<int> se[N];
int p[N];
int find(int x){
return p[x] == x ? x : p[x] = find(p[x]);
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) p[i] = i, se[i].insert(i);
while (m -- ){
int op, x, y;
cin >> op >> x >> y;
if (op == 1){
int px = find(x), py = find(y);
if (px == py) continue;
else{
p[px] = py;
//py祖宗
int k = 0;
//前10个
while (!se[px].empty() && k <= 10){
k ++;
int mx = *(--se[px].end());
se[py].insert(mx);
se[px].erase(mx);
}
}
}else{
//输出
int px = find(x);
if (se[px].size() < y) cout << -1 << '\n';
else{
vector<int> v;
while (y){
int mx = *(--se[px].end());
se[px].erase(mx);
v.push_back(mx);
y -- ;
if (!y){
cout << mx << '\n';
}
}
for (auto mx : v) se[px].insert(mx);
}
}
}
}