A - Spoiler
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = INT_MAX;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
string s;
cin >> s;
int f = 1;
for( auto i : s ){
if( i == '|' ) f ^= 1;
if( f and i != '|') cout << i;
}
return 0;
}
B - Delimiter
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = INT_MAX;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
vi a;
int x;
while( cin >> x ) a.push_back(x);
reverse(a.begin(), a.end());
for( auto i : a )
cout << i << "\n";
return 0;
}
C - A+B+C
先离线处理出所有可能组合出的数字。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = INT_MAX;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi a(n);
for (auto &i: a) cin >> i;
int m;
cin >> m;
vi b(m);
for (auto &i: b) cin >> i;
int l;
cin >> l;
vi c(l);
for (auto &i: c) cin >> i;
set<int> vis;
for (auto i: a)
for (auto j: b)
for (auto k: c)
vis.insert(i + j + k);
int q;
cin >> q;
for( int x ; q ; q -- ){
cin >> x;
if( vis.count(x) ) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
D - String Bags
其实是一个简单的01背包问题。
用\(f[i][j]\)表示前\(i\)个串拼出长度为\(j\)的前缀的最小花费。
现在对于一个给定的串,我们枚举他放置的位置,先看这个位置之前能不能被拼出来,再看能不能放进这个位置即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = INT_MAX;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
string t;
cin >> t;
int m = t.size();
int n;
cin >> n;
string s;
vector<int> f(m + 1, inf);
f[0] = 0;
for (int x; n; n--) {
cin >> x;
auto g = f;
for (int len; x; x--) {
cin >> s, len = s.size();
for (int p = 0; p + len <= m; p++) {
if (f[p] == inf) continue;
if (t.substr(p, s.size()) == s)
g[p + len] = min(g[p + len], f[p] + 1);
}
}
f.swap(g);
}
if (f.back() == inf) cout << "-1\n";
else cout << f.back() << "\n";
return 0;
}
还在群里学到了一个用map的写法
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = 1e9;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
string T;
cin >> T;
map<string, int> f;
f[""] = 0;
for (string s = ""; auto i: T)
s += i, f[s] = inf;
int n;
cin >> n;
for (int x; n; n--) {
cin >> x;
auto g = f;
for (string s, ns; x; x--) {
cin >> s;
for (auto [k, v]: f) {
ns = k + s;
if (v == inf or ns.size() > T.size() or g.count(ns) == 0)
continue;
g[ns] = min(g[ns], v + 1);
}
}
f.swap(g);
}
if (f[T] == inf) f[T] = -1;
cout << f[T] << "\n";
return 0;
}
E - Insert or Erase
单说插入和删除操作实际上都可以用链表\(O(1)\)的实现,难点是如何快速找到要插入或修改的位置。
我这里使用std::map<int,std::pair<int,int>>
来模拟了链表的执行过程。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = INT_MAX;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
map<int, pii> List;
for (int i = 1, x, lst = 0; i <= n; i++) {
cin >> x;
List[lst].second = x;
List[x] = pair(lst, inf);
lst = x;
}
int q;
cin >> q;
for (int op, lst, nxt, x; q; q--) {
cin >> op;
if (op == 1) {
cin >> lst >> x;
nxt = List[lst].second;
List[x] = pair(lst, nxt);
List[lst].second = List[nxt].first = x;
} else {
cin >> x;
tie(lst, nxt) = List[x];
List[x] = pair(-1, -1);
List[lst].second = nxt;
List[nxt].first = lst;
}
}
for (int i = List[0].second; i != inf; i = List[i].second)
cout << i << " ";
cout << "\n";
return 0;
}
F - Earn to Advance
一个比较板的dp。据说和某年的csp-j t2比较类似。
设 dp的状态为$f[i][j][x][y] \(表示走到\)(i,j)\(点且路径中经过\)p\(的最大值在\)(x,y)\(上,这样实际上就是\)O(n^4)\(的枚举就行。要注意的就是向下一步走的时候要判断\)p$最大值位置是否发生变化。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = LLONG_MAX;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector p(n, vi(n));
for (auto &it: p)
for (auto &i: it) cin >> i;
vector r(n, vi(n - 1));
for (auto &it: r)
for (auto &i: it) cin >> i;
vector d(n - 1, vi(n));
for (auto &it: d)
for (auto &i: it) cin >> i;
vector f(n, vector(n, vector(n, vector(n, pair(inf, -inf)))));
f[0][0][0][0] = pair(0, 0);
auto calc = [](int a, int b, int c) {
if (a >= b) return 0ll;
return (b - a + c - 1) / c;
};
auto cmp = [](pii x, pii y) {
if (x.first != y.first) return x.first < y.first;
return x.second > y.second;
};
for (int i = 0, wait, newX, newY, newDis, newLst; i < n; i++)
for (int j = 0; j < n; j++)
for (int x = 0; x <= i; x++)
for (int y = 0; y <= j; y++) {
const auto &[dis, lst] = f[i][j][x][y];
if (dis == inf) continue;
if (i + 1 < n) {
wait = calc(lst, d[i][j], p[x][y]);
newX = x, newY = y;
if (p[i + 1][j] > p[x][y]) newX = i + 1, newY = j;
newDis = dis + wait + 1, newLst = lst + wait * p[x][y] - d[i][j];
f[i + 1][j][newX][newY] = min(f[i + 1][j][newX][newY], pair(newDis, newLst),cmp);
}
if (j + 1 < n) {
wait = calc(lst, r[i][j], p[x][y]);
newX = x, newY = y;
if (p[i][j + 1] > p[x][y]) newX = i, newY = j + 1;
newDis = dis + wait + 1, newLst = lst + wait * p[x][y] - r[i][j];
f[i][j + 1][newX][newY] = min(f[i][j + 1][newX][newY], pair(newDis, newLst), cmp);
}
}
int res = inf;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
res = min(res, f[n - 1][n - 1][i][j].first);
cout << res << "\n";
return 0;
}
标签:AtCoder,Beginner,int,auto,cin,344,lst,using,inf
From: https://www.cnblogs.com/PHarr/p/18064240