AtCoder Beginner Contest 328
A - Not Too Hard
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, x;
cin >> n >> x;
int res = 0;
for (int i = 1, s; i <= n; i ++) {
cin >> s;
if (s <= x)
res += s;
}
cout << res << "\n";
return 0;
}
B - 11/11
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
int cnt = 0;
for(int i = 1, d, x, y; i <= n; i ++) {
cin >> d;
x = i % 10, y = i;
while(y) {
if(y % 10 == x) y /= 10;
else x = -1, y = 0;
}
if(x == -1) continue;
for( int j = x; j <= d; j = j * 10 + x)
cnt ++;
}
cout << cnt << "\n";
return 0;
}
C - Consecutive
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, q;
cin >> n >> q;
string s;
cin >> s, s = " " + s;
vi a(n);
for(int i = 1; i < n; i ++)
a[i] = (s[i] == s[i+1]) + a[i-1];
for(int l, r; q; q --) {
cin >> l >> r, r --;
cout << a[r] - a[l-1] << "\n";
}
return 0;
}
D - Take ABC
用栈模拟一下,每次判断最后三个是不是ABC
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
string s;
cin >> s;
vector<char> stk;
for(auto i : s) {
stk.push_back(i);
while(stk.size() >= 3 and stk[stk.size() - 3] == 'A' and stk[stk.size() - 2] == 'B' and stk[stk.size() - 1] == 'C')
stk.pop_back(), stk.pop_back(), stk.pop_back();
}
for(auto i : stk)
cout << i;
return 0;
}
E - Modulo MST
因为\(n\)很小,所以我们可以用一个二进制数来表示那些点与\(1\)联通,如果一条边可以被选择,这一定是一个点与 1 联通,另一个店不联通。然后我们可以用set
记录下每种状态所有选边的权重之和。剩下的就是简单的bfs。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
vector<array<int,3>> edge(m);
for(auto &[u, v, w] : edge) cin >> u >> v >> w, u --, v --;
vector<set<int>> f(1 << n);
queue<int> q;
f[1].insert(0), q.push(1);
vi vis(1 << n);
while(not q.empty()) {
int x = q.front();
q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(const auto &[u, v, w] : edge){
if(((x >> u) & 1) == ((x >> v) & 1)) continue;
int y = x | (1 << u) | (1 << v);
for(auto i : f[x])
f[y].insert((i + w) % k);
q.push(y);
}
}
cout << *f[(1 << n) - 1].begin() << "\n";
return 0;
}
F - Good Set Query
我们可以把一个条件当做是一条从\(a\)到\(b\)的有向有权边,边权为\(d\)。同时建立一个反向边,\(-d\)。然后我们加入条件就可以转换为向生成树上建边。这样的话,我们维护出dis[i]
表示从跟到\(i\)的路径长度,这样生成树两点\(x,y\)之间的距离就是\(dis[x]-dis[y]\)。
对于一条边,加入有两种情况。
- \(a,b\)点不联通,此时说明两个之间没有任何限制条件。直接加入就好了。
- \(a,b\)点联通,则我们这条边加入不会影响连通性,但是我们判断这条加入是否会冲突,也就是判断\(d\)是否等于\(dis[x]-dis[y]\)
上述内容都可以使用带权并查集来维护。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
struct dsu {
vi fa, dis;
dsu(int n = 1) : fa(n + 1, -1) , dis(n + 1) {};
int getfa(int x) {
if(fa[x] == -1) return x;
int f = fa[x];
fa[x] = getfa(fa[x]),dis[x] = dis[f] + dis[x];
return fa[x];
}
bool merge(int x, int y, int w) {
int fx = getfa(x), fy = getfa(y);
if(fx != fy){
fa[fx] = fy;
dis[fx] = - dis[x] + dis[y] + w;
return true;
}else{
return dis[x] - dis[y] == + w;
}
}
};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, q;
cin >> n >> q;
dsu d(n);
for(int i = 1,x , y, w; i <= q ; i ++) {
cin >> x >> y >> w;
if(d.merge(x, y, w)) cout << i << " ";
}
cout << "\n";
return 0;
}