AtCoder Beginner Contest 391
A - Lucky Direction
点击查看代码
void solve() {
std::vector<std::string> a{"N","S", "W", "E", "NE", "SW", "NW", "SE"};
std::string s;
std::cin >> s;
int p = std::find(a.begin(), a.end(), s) - a.begin();
std::cout << a[p ^ 1] << "\n";
}
B - Seek Grid
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> s(n), t(m);
for (int i = 0; i < n; ++ i) {
std::cin >> s[i];
}
for (int i = 0; i < m; ++ i) {
std::cin >> t[i];
}
auto check = [&](int a, int b) -> bool {
for (int i = 0; i < m; ++ i) {
for (int j = 0; j < m; ++ j) {
if (s[a + i][b + j] != t[i][j]) {
return false;
}
}
}
return true;
};
for (int i = 0; i + m - 1 < n; ++ i) {
for (int j = 0; j + m - 1 < n; ++ j) {
if (check(i, j)) {
std::cout << i + 1 << " " << j + 1 << "\n";
return;
}
}
}
}
C - Pigeonhole Query
题意:
记录每个笼子的鸽子数和每个鸽子在哪个笼子即可。
点击查看代码
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> cnt(n, 1), p(n);
std::iota(p.begin(), p.end(), 0);
int ans = 0;
while (q -- ) {
int op;
std::cin >> op;
if (op == 1) {
int x, y;
std::cin >> x >> y;
-- x, -- y;
if (cnt[p[x]] == 2) {
-- ans;
}
-- cnt[p[x]];
if (cnt[y] == 1){
++ ans;
}
++ cnt[y];
p[x] = y;
} else {
std::cout << ans << "\n";
}
}
}
D - Gravity
题意:
模拟消除即可。每次模拟一行的消除,每次找每行高度最低的方块里高度最高的。最多模拟
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> ans(n, 2e9);
std::vector<std::vector<std::pair<int, int> > > a(m);
for (int i = 0; i < n; ++ i) {
int x, y;
std::cin >> x >> y;
-- x;
a[x].push_back({y, i});
}
for (int i = 0; i < m; ++ i) {
std::sort(a[i].begin(), a[i].end(), std::greater<>());
}
int time = 0;
auto move = [&]() -> bool {
int max = 0;
for (int i = 0; i < m; ++ i) {
if (a[i].empty()) {
return false;
}
max = std::max({max, a[i].back().first - time, 1});
}
int t = max - 1;
for (int i = 0; i < m; ++ i) {
ans[a[i].back().second] = time + t;
a[i].pop_back();
}
time += t;
return true;
};
while (move());
int q;
std::cin >> q;
while (q -- ) {
int t, x;
std::cin >> t >> x;
-- x;
if (ans[x] >= t) {
std::cout << "Yes\n";
} else {
std::cout << "No\n";
}
}
}
E - Hierarchical Majority Vote
题意:一个
可以用递归求出最终结果,每次分成三份一直递归到长度为1就行。然后得到我们需要变成的结果v(v=0或者v=1),最后依然可以递归求,求出每个部分变成v需要几次操作,取最小的两个部分即可。
点击查看代码
void solve() {
int n;
std::cin >> n;
n = std::pow(3, n);
std::string s;
std::cin >> s;
auto dfs = [&](auto self, int l, int r) -> int {
if (l == r) {
return s[l - 1] - '0';
}
int len = (r - l + 1) / 3;
return self(self, l, l + len - 1) + self(self, l + len, l + 2 * len - 1) + self(self, l + 2 * len, r) >= 2;
};
int v = dfs(dfs, 1, n);
auto dfs1 = [&](auto self, int l, int r) -> int {
if (l == r) {
return s[l - 1] - '0' == v;
}
int len = (r - l + 1) / 3;
int a = self(self, l, l + len - 1);
int b = self(self, l + len, l + 2 * len - 1);
int c = self(self, l + 2 * len, r);
std::vector<int> d{a, b, c};
std::sort(d.begin(), d.end());
return d[0] + d[1];
};
// std::cout << v << "\n";
std::cout << dfs1(dfs1, 1, n) << "\n";
}
F - K-th Largest Triplet
题意:给你三个数组,求所有
三个数组从大到小排序后用优先级队列模拟即可,一开始把
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<i64> a(n), b(n), c(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < n; ++ i) {
std::cin >> b[i];
}
for (int i = 0; i < n; ++ i) {
std::cin >> c[i];
}
std::sort(a.begin(), a.end(), std::greater<i64>());
std::sort(b.begin(), b.end(), std::greater<i64>());
std::sort(c.begin(), c.end(), std::greater<i64>());
auto get = [&](int i, int j, int k) -> i64 {
return a[i] * b[j] + b[j] * c[k] + a[i] * c[k];
};
std::priority_queue<std::array<i64, 4>> heap;
heap.push({get(0, 0, 0), 0, 0, 0});
std::set<std::array<int, 3> > s;
s.insert({0, 0, 0});
while ( -- m) {
auto [val, i, j, k] = heap.top(); heap.pop();
if (i + 1 < n && !s.count({i + 1, j, k})) {
s.insert({i + 1, j, k});
heap.push({get(i + 1, j, k), i + 1, j, k});
}
if (j + 1 < n && !s.count({i, j + 1, k})) {
s.insert({i, j + 1, k});
heap.push({get(i, j + 1, k), i, j + 1, k});
}
if (k + 1 < n && !s.count({i, j, k + 1})) {
s.insert({i, j, k + 1});
heap.push({get(i, j, k + 1), i, j, k + 1});
}
}
std::cout << heap.top()[0] << "\n";
}
G - Many LCS
题意:给你一个长度为
听说是经典dp,但我是第一次做。
回忆求最长公共子序列的dp方程,发现如果
记
dp状态定义只要满足对于每种情况都恰好有一个状态可以表示它,就是合理的。那么我们这样定义的dp状态,是正确的。
于是记
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::string str;
std::cin >> str;
auto s_to_dp = [&](int x) -> std::vector<int> {
std::vector<int> f(n + 1);
for (int i = 0; i < n; ++ i) {
if (x >> i & 1) {
f[i + 1] = f[i] + 1;
} else {
f[i + 1] = f[i];
}
}
return f;
};
auto dp_to_s = [&](std::vector<int> f) -> int {
int res = 0;
for (int i = 0; i < n; ++ i) {
if (f[i + 1] > f[i]) {
res += 1 << i;
}
}
return res;
};
std::vector<Z> f(1 << n);
f[0] = 1;
for (int j = 1; j <= m; ++ j) {
std::vector<Z> g(1 << n);
for (int s = 0; s < 1 << n; ++ s) {
if (f[s] == 0) {
continue;
}
auto tmp = s_to_dp(s); //dp[1~n][j - 1]
for (char c = 'a'; c <= 'z'; ++ c) {
std::vector<int> dp(n + 1); //dp[1~n][j]
for (int i = 1; i <= n; ++ i) {
//dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
dp[i] = std::max(dp[i - 1], tmp[i]);
//dp[i][j] = dp[i - 1][j - 1] + 1
if (c == str[i - 1]) {
dp[i] = std::max(dp[i], tmp[i - 1] + 1);
}
}
int ns = dp_to_s(dp);
g[ns] += f[s];
}
}
f = g;
}
std::vector<Z> ans(n + 1);
for (int i = 0; i < 1 << n; ++ i) {
ans[__builtin_popcount(i)] += f[i];
}
for (int i = 0; i <= n; ++ i) {
std::cout << ans[i] << " \n"[i == n];
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!