Codeforces-Round-897-&-AtCoder-Beginner-Contest-311
也可以参考网上的其他题解:codeforces https://zhuanlan.zhihu.com/p/655687735
atcoder https://www.cnblogs.com/Lanly/p/17574427.html
以下是我的简单思路和代码
Codeforces Round 897
A. A
#include <bits/stdc++.h>
#define int long long
/*
思路:让我们从最小数中减去 n, 从第二个最小数中减去 n−1,从第三个 …中减去 n−2,再从最大数中减去 1
显然没有更好的结果
*/
void solve() {
int n;
std::cin >> n;
std::vector<std::array<int, 2>> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i][0];
a[i][1] = i + 1;
}
sort(a.begin(), a.end());
std::vector<int> ans(n + 1);
int cnt = n;
for (auto [k, idx] : a) {
ans[idx] = cnt--;
}
for (int i = 1; i <= n; i++) {
std::cout << ans[i] << ' ';
}
std::cout << '\n';
}
signed main() {
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
B. B
思路: 考虑给定串前后的对应部分原来是否相同,若不同则需要且仅需要在这两个位置中改一个,若相同则可以都不改或者都改。特别地,若 n 为奇数则中间位置改不改都行。
#include <bits/stdc++.h>
#define int long long
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
// 记录有多少对不同
int cnt = 0;
for (int i = 0, j = n - 1; i < j; i++, j--) {
if (s[i] != s[j]) {
cnt++;
}
}
std::string ans(n + 1, '0');
// 异或运算 与 1 异或才会改变
// 至少需要修改 cnt 个, 最多只能修改 n - cnt 个, 如果 n 是奇数, 中间的一位可修改可不修改,所以:i += 1 + (n % 2 == 0)
for (int i = cnt; i <= n - cnt; i += 1 + (n % 2 == 0)) {
ans[i] = '1';
}
std::cout << ans << '\n';
}
signed main() {
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
C. C
#include <bits/stdc++.h>
#define int long long
/*
思路: 理解题意发现并不难, 如果s[0] > 1, 则R最大为1
如果是序列 0 1 2 3, 则R最大是4。
不多说了,看代码吧
*/
void solve() {
int n;
std::cin >> n;
int x;
std::map<int, int> mp;
for (int i = 0; i < n; i++) {
std::cin >> x;
mp[x]++;
}
int p = 0;
for (int i = 0; i <= n; i++) {
if (!mp.count(i)) {
p = i;
break;
}
}
while (1) {
std::cout << p << std::endl;
int q;
std::cin >> q;
if (q == -1) {
break;
}
p = q;
}
}
signed main() {
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
D. d
#include <bits/stdc++.h>
#define int long long
/*
思路: 找环, 建有向边 i -> a[i], 表示第 i 个要变为 a[i],
通过观察 如果存在一个环的大小不等于k, 这个是肯定不可以构造成功的, k = 1 的时候特判一下
*/
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n + 1);
int f = 0;
for (int i = 1; i <= n; i++) {
int x;
std::cin >> x;
a[i] = x;
if (i != x) f = 1;
}
if (f && k == 1) {
std::cout << "NO\n";
return;
}
std::vector<int> vis(n + 1);
std::vector<int> st(n + 1);
for (int i = 1; i <= n; i++) {
if (!st[i]) {
int cnt = 0;
for (int j = i; ; j = a[j]) {
if (st[j] && st[j] != i) {
cnt = k;
break;
}
st[j] = i;
vis[j]++;
if (vis[j] == 3) {
break;
}
if (vis[j] == 2) {
cnt++;
}
}
if (cnt != k) {
std::cout << "NO\n";
return;
}
}
}
std::cout << "YES\n";
}
signed main() {
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
E. E1
#include <bits/stdc++.h>
#define int long long
int query(int x) {
std::cout << "? " << x << std::endl;
int res;
std::cin >> res;
return res;
}
void solve() {
int n, k;
std::cin >> n >> k;
int ans = 0;
for (int i = 1; i <= n; i += k) {
if (i + k - 1 > n) {
int m = n - i + 1;
ans = ans ^ query(n - m / 2 - k + 1) ^ query(n - k + 1);
break;
}
// std::cout << "!!!" << i << '\n';
ans ^= query(i);
}
std::cout << "! " << ans << std::endl;
}
signed main() {
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
F. E2
#include <bits/stdc++.h>
#define int long long
int query(int x) {
std::cout << "? " << x << std::endl;
int res;
std::cin >> res;
return res;
}
void solve() {
int n, k;
std::cin >> n >> k;
int ans = 0;
for (int i = 1; i <= n; i += k) {
if (i + k - 1 > n) {
int m = n - i + 1;
ans = ans ^ query(n - m / 2 - k + 1) ^ query(n - k + 1);
break;
}
// std::cout << "!!!" << i << '\n';
ans ^= query(i);
}
std::cout << "! " << ans << std::endl;
}
signed main() {
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
G. F
AtCoder Beginner Contest 311 A - F
H、a
#include <bits/stdc++.h>
int main() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
// 了解set的用法:https://www.runoob.com/cplusplus/cpp-libs-set.html
std::set<char> se;
for (int i = 0; i < n; i++) {
se.insert(s[i]);
if (se.size() == 3) {
std::cout << i + 1 << '\n';
return 0;
}
}
return 0;
}
I、b
#include <bits/stdc++.h>
/*
思路: 统计每一天有空的人数, 取有空人数 = n 的天 连续的最大值
*/
int main() {
int n, m;
std::cin >> n >> m;
std::vector<int> cnt(m);
for (int i = 0; i < n; i++) {
std::string s;
std::cin >> s;
for (int j = 0; j < m; j++) {
if (s[j] == 'o') {
cnt[j]++;
}
}
}
int ans = 0, t = 0;
for (int i = 0; i < m; i++) {
if (cnt[i] == n) {
t++;
ans = std::max(ans, t);
} else {
t = 0;
}
}
std::cout << ans << '\n';
return 0;
}
J、c
#include <bits/stdc++.h>
/*
思路: 因为有n条边, 所以每个连通块一定存在一个环。任意选择一个开始操作即可,见代码
*/
signed main() {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
std::vector<int> vis(n + 1), ans;
// 这里i初始可以是 1 - n 的任意值
for (int i = 1; ; i = a[i]) {
vis[i]++;
// 说明这个环都已经全部被加入到ans中了,退出循环
if (vis[i] == 3) {
break;
}
// 第二次遍历到, 说明这个一定是环中的一个节点
if (vis[i] == 2) {
ans.push_back(i);
}
}
std::cout << ans.size() << '\n';
for (auto x : ans) {
std::cout << x << ' ';
}
std::cout << '\n';
return 0;
}
K、d
#include <bits/stdc++.h>
int n, m;
const int MAX = 210;
std::string a[MAX];
int vis[MAX][MAX];
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
void dfs(int x, int y) {
vis[x][y] = 1;
// 选择四个方向
for (int i = 0; i < 4; i++) {
int tx = x, ty = y;
while (a[tx + dx[i]][ty + dy[i]] != '#') {
vis[tx][ty] = 1;
tx += dx[i], ty += dy[i];
}
// 此时走到 a[tx][ty],重新选择方向
// 如果这个格子被走过的话就 一定不用重新遍历了
if (!vis[tx][ty]) {
dfs(tx, ty);
}
}
}
int main() {
std::cin >> n >> m;
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
dfs(1, 1);
int ans = 0;
// 记录答案
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (vis[i][j]) {
ans++;
}
}
}
std::cout << ans << '\n';
return 0;
}
L、e
#include <bits/stdc++.h>
/*
题意: 转化题意就是求 全部无洞正方形子矩阵的数量
把有洞的方格设为 0, 其他设为 1 统计全为 1 的正方形子矩阵问题就转化为 这道题:https://leetcode.cn/problems/count-square-submatrices-with-all-ones/description/?envType=daily-question&envId=2025-08-20
这道题正好是今天 leetcode 的每日一题
可以看这一篇题解:https://leetcode.cn/problems/count-square-submatrices-with-all-ones/solutions/3751608/tu-jie-dong-tai-gui-hua-jian-ji-xie-fa-p-1kiy/?envType=daily-question&envId=2025-08-20
以下是示例代码
*/
const int N = 3010;
int a[N][N];
long long dp[N][N];
int main() {
int n, m, k;
std::cin >> n >> m >> k;
while (k--) {
int x, y;
std::cin >> x >> y;
a[x][y] = 1;
}
long long ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i][j] == 0) {
dp[i][j] = std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;
ans += dp[i][j];
}
}
}
std::cout << ans << '\n';
return 0;
}
M、f
#include <bits/stdc++.h>
const int MOD = 998244353;
/*
思路: 定义 dp[i][j]表示前i列,其中第i列的情况是,j 行及以下都是黑色,以上都是白色 的方案数。
详细见题解:https://www.cnblogs.com/Lanly/p/17574427.html
*/
int main() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == '#') {
if (i < n - 1) {
a[i + 1][j] = '#';
if (j < m - 1) {
a[i + 1][j + 1] = '#';
}
}
}
}
}
std::vector<int> dp(n + 1, 0);
// 初始化 第 -1 列全为白色这一种方案
dp[n] = 1;
for (int i = 0; i < m; i++) {
std::vector<int> dp2(n + 1, 0);
int sufsum = 0;
for (int j = n; j >= 0; j--) {
sufsum = (sufsum + dp[j]) % MOD;
if (j > 0 && a[j - 1][i] == '#') {
continue;
}
if (j > 0) {
dp2[j] = dp[j - 1] + sufsum;
} else {
dp2[j] = sufsum;
}
dp2[j] %= MOD;
}
dp = dp2;
}
int ans = 0;
for (int i = 0; i <= n; i++) {
ans = (ans + dp[i]) % MOD;
}
std::cout << ans << '\n';
return 0;
}
N、g
待做
浙公网安备 33010602011771号