AtCoder Beginner Contest 375
1|0A - Seats
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
string S;
cin >> S;
int res = 0;
for(int i = 0; i + 2 < N; i ++)
if(S[i] == '#' and S[i + 2] == '#' and S[i + 1] == '.')
res ++;
cout << res;
return 0;
}
2|0B - Traveling Takahashi Problem
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
double res = 0;
int lx = 0, ly = 0;
for(int i = 1, x, y; i <= N; i ++) {
cin >> x >> y;
res += hypot(x - lx, y - ly);
lx = x, ly = y;
}
res += hypot(lx, ly);
cout << fixed << setprecision(20) << res;
return 0;
}
3|0C - Spiral Rotation
通过找规律发现,题目可以这样理解。
把矩形分成N2圈,从外向内,第一圈旋转π2,第二圈旋转2π2,第三圈旋转3π2,第四圈旋转4π2,并以此类推。
知道这个规律的话,我们就可以O(1)计算出每个点被移动到哪里。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
vector A(N + 1, vector<char>(N + 1));
for(int i = 1; i <= N; i ++)
for(int j = 1; j <= N; j ++)
cin >> A[i][j];
vector B(N + 1, vector<char>(N + 1));
for(int i = 1; i <= N; i ++) {
for(int j = 1; j <= N; j ++) {
int t = min({i , j , N - i + 1, N - j + 1});
int n = N - 2 * (t - 1), p = t % 4, q = 2 * t - 2;
int x = i, y = j;
while(p --) {
int nx = y, ny = n - x + 1 + q;
x = nx, y = ny;
}
B[x][y] = A[i][j];
}
}
for(int i = 1; i <= N; i ++){
for(int j = 1;j <= N; j ++){
cout << B[i][j];
}
cout << "\n";
}
return 0;
}
4|0D - ABA
可以分别统计前后缀每种字母出现的次数,然后可以直接枚举出回文串的样子。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
string s;
cin >> s;
int n = s.size();
vi pre(26), suf(26);
for(int i = 2; i < n; i ++)
suf[s[i] - 'A'] ++;
pre[s[0] - 'A'] ++;
int res = 0;
for(int i = 1; i + 1 < n; i ++){
for(int j = 0; j < 26; j ++)
res += pre[j] * suf[j];
pre[s[i] - 'A'] ++;
suf[s[i + 1] - 'A'] --;
}
cout << res;
return 0;
}
5|0E - 3 Team Division
这里的换并不是交换,而是可以直接换,因此我们可以直接 dp。
这状态为f[i][x][y]表示前i个人,当前第1队权值和为x,第 2 队权值和为y的最小操作次数。
然后可以直接暴力枚举状态并转移即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
const int inf = INT_MAX / 2;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
int sum = 0;
vector<pii> p(n);
for(auto &[a, b] : p)
cin >> a >> b, a --, sum += b;
if(sum % 3 != 0) {
cout << "-1\n";
return 0;
}
sum /= 3;
vector f(sum + 1, vi(sum + 1, inf));
f[0][0] = 0;
for(int pre = 0;auto &[a , b] : p){
pre += b;
vector g(sum + 1, vi(sum + 1, inf));
for(int x = 0, y; x < 3; x ++ ) {
y = (x != a);
for(int i = 0; i <= sum; i ++){
for(int j = 0; j <= sum; j ++){
if(x == 0) {
if(i - b >= 0) g[i][j] = min(g[i][j], f[i - b][j] + y);
}else if(x == 1){
if(j - b >= 0) g[i][j] = min(g[i][j], f[i][j - b] + y);
} else {
if(pre - i - j - b >= 0) g[i][j] = min(g[i][j], f[i][j] + y);
}
}
}
}
f = move(g);
}
int res = f[sum][sum];
if(res == inf) res = -1;
cout << res;
return 0;
}
6|0F - Road Blocked
我们可以离线,然后倒序做,此时删边操作就变成了加边。
每加入一条边,我们就可以把边所影响的点对进行松弛操作,因为加边的次数不超过300,因此总的复杂度就是 floyd
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
const int inf = LLONG_MAX / 3;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, q;
cin >> n >> m >> q;
vector<array<int,3>> edge(m);
for(auto &[u, v, w] : edge)
cin >> u >> v >> w;
vector<bool> closed(m);
vector<vi> query(q);
for(int op, x, y; auto &it : query) {
cin >> op;
if(op == 1) {
cin >> x, x --;
closed[x] = true;
it.push_back(x);
} else {
cin >> x >> y;
it.push_back(x);
it.push_back(y);
}
}
vector dis(n + 1, vi(n + 1, inf));
for(int i = 1; i <= n; i ++) dis[i][i] = 0;
for(int i = 0; i < m; i ++) {
if(closed[i]) continue;
const auto &[u, v, w] = edge[i];
dis[u][v] = dis[v][u] = min(dis[u][v], w);
}
for(int k = 1; k <= n; k ++)
for(int i = 1; i <= n; i ++) {
if(i == k) continue;
for(int j = 1; j < i; j ++) {
if(j == k) continue;
dis[i][j] = dis[j][i] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
ranges::reverse(query);
vi res;
for(auto it : query) {
if(it.size() == 1) {
const auto &[u, v, w] = edge[it[0]];
dis[u][v] = dis[v][u] = min(dis[u][v], w);
for(int i = 1; i <= n; i ++ )
for(int j = 1; j < i; j ++ )
dis[i][j] = dis[j][i] = min({dis[i][j], dis[i][u] + w + dis[v][j], dis[i][v] + w + dis[u][j]});
} else {
int x = it[0], y = it[1];
if(dis[x][y] == inf) res.push_back(-1);
else res.push_back(dis[x][y]);
}
}
ranges::reverse(res);
for(auto i : res) cout << i << "\n";
return 0;
}
7|0G - Road Blocked 2
题目要求的是,哪些边被所有的最短路经过。
首先我们考虑如何求出一条边是否被最短路经过。我们从1求一遍最短路记为d1,从n求一遍最短路记为dn。
对于一条边(u,v,w)如果满足d1[u]+w+dn[v]=d1[n]则证明这条边在至少在一条最短路上。
我们在求最短路的过程中,还可以dp 求出从起点到当前点最短路的方案数,以1为起点记为c1,以n为起点记为cn。
那么如果c1[u]×cn[v]=c1[n]则说明当前边被所有的最短路经过。
这里的方案数可能分到,我们比较模意义下即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
const int inf = LLONG_MAX / 2;
const int mod = 998244353;
struct mint {
int x;
mint(int x = 0) : x(x) {}
void norm(){
x = (x % mod + mod) % mod;
return;
}
mint &operator=(int o) { return x = o, *this; }
mint &operator+=(mint o) { return (x += o.x) >= mod && (x -= mod), *this; }
mint &operator-=(mint o) { return (x -= o.x) < 0 && (x += mod), *this; }
mint &operator*=(mint o) { return x = (i64) x * o.x % mod, *this; }
mint &operator^=(int b) {
mint w = *this;
mint ret(1);
for (; b; b >>= 1, w *= w) if (b & 1) ret *= w;
return x = ret.x, *this;
}
mint &operator/=(mint o) { return *this *= (o ^= (mod - 2)); }
friend mint operator+(mint a, mint b) { return a += b; }
friend mint operator-(mint a, mint b) { return a -= b; }
friend mint operator*(mint a, mint b) { return a *= b; }
friend mint operator/(mint a, mint b) { return a /= b; }
friend mint operator^(mint a, int b) { return a ^= b; }
friend bool operator==(mint a, mint b) {
a.norm(), b.norm();
return a.x == b.x;
}
};
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, q;
cin >> n >> m;
vector<array<int,3>> edge(m);
vector<vector<pii>> e(n + 1);
for(auto &[u, v, w] : edge) {
cin >> u >> v >> w;
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
auto dij = [=](int s) {
vi dis(n + 1, inf), vis(n + 1);
vector<mint> cnt(n + 1);
dis[s] = 0, cnt[s] = 1;;
priority_queue<pii,vector<pii>, greater<>> heap;
heap.emplace(0, s);
while(not heap.empty()) {
auto [d, x] = heap.top();
heap.pop();
if(vis[x]) continue;
vis[x] = 1;
for(auto [y, w] : e[x]) {
if(dis[y] < d + w) continue;
if(dis[y] == d + w) {
cnt[y] += cnt[x];
continue;
}
dis[y] = d + w, cnt[y] = cnt[x];
heap.emplace(dis[y], y);
}
}
return pair(dis, cnt);
};
auto [d1, c1] = dij(1);
auto [dn, cn] = dij(n);
for(auto &[u, v, w] : edge){
if(d1[u] + w + dn[v] == d1[n] and c1[u] * cn[v] == c1[n])
cout << "Yes\n";
else if(d1[v] + w + dn[u] == d1[n] and c1[v] * cn[u] == c1[n])
cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
另一个思路是,我们把所有至少被一条最短路经过的边取出来,建新图。对新图求一下桥即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int long long
using vi = vector<int>;
using pii = pair<int,int>;
const int inf = LLONG_MAX / 2;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, q;
cin >> n >> m;
vector<array<int,3>> edge(m);
vector<vector<pii>> e(n + 1);
for(auto &[u, v, w] : edge) {
cin >> u >> v >> w;
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
auto dij = [=](int s) {
vi dis(n + 1, inf), vis(n + 1);
dis[s] = 0;
priority_queue<pii,vector<pii>, greater<>> heap;
heap.emplace(0, s);
while(not heap.empty()) {
auto [d, x] = heap.top();
heap.pop();
if(vis[x]) continue;
vis[x] = 1;
for(auto [y, w] : e[x]) {
if(vis[y]) continue;
if(dis[y] <= d + w) continue;
dis[y] = d + w;
heap.emplace(dis[y], y);
}
}
return dis;
};
auto d1 = dij(1), dn = dij(n);
vector<vector<pii>> g(n + 1);
for(int i = 0; i < m; i ++) {
const auto &[u, v, w] = edge[i];
if(d1[u] + w + dn[v] == d1[n])
g[u].emplace_back(v, i), g[v].emplace_back(u, i);
else if(d1[v] + w + dn[u] == d1[n])
g[u].emplace_back(v, i), g[v].emplace_back(u, i);
}
vi bridges(m), dfn(n + 1), low(n + 1), fa(n + 1);
int cnt = 0;
auto tarjan = [&](auto &&tarjan, int x) -> void {
low[x] = dfn[x] = ++ cnt;
for(auto [y, id]: g[x]) {
if(!dfn[y]) {
fa[y] = x, tarjan(tarjan, y);
low[x] = min(low[x], low[y]);
if(low[y] > dfn[x]) bridges[id] = 1;
} else if(fa[x] != y) {
low[x] = min(low[x], dfn[y]);
}
}
return;
};
for(int i = 1; i <= n; i ++)
if(!dfn[i]) tarjan(tarjan, i);
for(auto i : bridges){
if(i) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
__EOF__

本文作者:PHarr
本文链接:https://www.cnblogs.com/PHarr/p/18462861.html
关于博主:前OIer,SMUer
版权声明:CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
本文链接:https://www.cnblogs.com/PHarr/p/18462861.html
关于博主:前OIer,SMUer
版权声明:CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2023-10-13 2021 China Collegiate Programming Contest (CCPC) Guilin Site
2022-10-13 数据结构实验(四)栈与队列的操作与应用
2022-10-13 数据结构(二)线性表
2022-10-13 数字逻辑与数字系统(一)数字逻辑基础