A - 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;
}
B - 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;
}
C - Spiral Rotation
通过找规律发现,题目可以这样理解。
把矩形分成\(\frac N 2\)圈,从外向内,第一圈旋转\(\frac \pi 2\),第二圈旋转\(2\frac{\pi}{2}\),第三圈旋转\(3\frac \pi 2\),第四圈旋转\(4\frac{\pi}{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;
}
D - 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;
}
E - 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;
}
F - 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;
}
G - Road Blocked 2
题目要求的是,哪些边被所有的最短路经过。
首先我们考虑如何求出一条边是否被最短路经过。我们从\(1\)求一遍最短路记为\(d1\),从\(n\)求一遍最短路记为\(dn\)。
对于一条边\((u,v,w)\)如果满足\(d1[u] + w + dn[v] = d1[n]\)则证明这条边在至少在一条最短路上。
我们在求最短路的过程中,还可以dp 求出从起点到当前点最短路的方案数,以\(1\)为起点记为\(c1\),以\(n\)为起点记为\(cn\)。
那么如果\(c1[u]\times 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;
}
标签:AtCoder,Beginner,int,mint,cin,long,vector,using,375
From: https://www.cnblogs.com/PHarr/p/18462861