AtCoder Beginner Contest 258 题解

只有 ABCDEG 的题解。

A

模拟。

代码
void mian() {
int x; scanf("%d", &x);
if (x < 60) printf("21:%02d\n", x);
else printf("22:%02d\n", x - 60);
}

B

模拟。

不要读错题!!不能拐弯!!

代码
const int N = 10;
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dy[] = {1, 0, -1, 1, -1, 1, 0, -1};
int n, a[N + 10][N + 10];
ll ans;
void mian() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%1d", &a[i][j]);
for (int k = 0; k < 8; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
int x = i, y = j;
ll now = 0;
for (int step = 1; step <= n; step++) {
now = now * 10 + a[x][y];
int nx = x + dx[k], ny = y + dy[k];
if (nx == 0) nx = n;
if (ny == 0) ny = n;
if (nx == n + 1) nx = 1;
if (ny == n + 1) ny = 1;
x = nx, y = ny;
}
ans = max(ans, now);
}
printf("%lld\n", ans);
}

C

维护一下每次操作 1 后字符串的开始位置在原字符串的位置即可。

代码
const int N = 5e5;
int n, q;
char s[N + 10];
void mian() {
scanf("%d%d%s", &n, &q, s);
int p = 0;
while (q--) {
int opt, x; scanf("%d%d", &opt, &x);
if (opt == 1) p = (p - x) % n;
else printf("%c\n", s[((p + x - 1) % n + n) % n]);
}
}

D

首先枚举要玩的前缀 1i。然后考虑怎么分配这 x 次。

贪心:b 最小的要被分到的最多,可以用微调法证明。

代码
const int N = 2e5;
int n, a[N + 10], b[N + 10], m;
ll sum[N + 10];
int mn[N + 10];
void mian() {
scanf("%d%d", &n, &m);
mn[0] = 0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
scanf("%d%d", a + i, b + i);
sum[i] = sum[i - 1] + a[i] + b[i];
mn[i] = min(mn[i - 1], b[i]);
}
ll ans = 0x3f3f3f3f3f3f3f3f;
for (int i = 1; i <= n; i++)
ans = min(ans, sum[i - 1] + a[i] + 1LL * mn[i] * (m - i + 1));
printf("%lld\n", ans);
}

E

预处理以每个 1in 作为“起点”时,对应的“终点”是什么。然后倍增。

注意这个题最大的一个坑是“终点”和“起点”间的距离可以是 109,所以不能简简单单的只处理前缀和!!

代码
const int N = 2e5, K = 40;
int n, q, x, a[N + 10], res[N + 10], to[K + 5][N + 10];
ll sum[N * 2 + 10], sum2[N + 10];
ll getsum(int l, int r) {
l--, r--;
int l1 = l / n, l2 = l % n;
int r1 = r / n, r2 = r % n;
if (l1 == r1) return sum[r2 + 1] - sum[l2];
else return sum2[l2 + 1] + sum[r2 + 1] + (r1 - l1 - 1) * sum[n];
}
void count(int p) {
int l = p, r = p + 1000000000, _l = l;
while (l < r) {
int mid = (l + r) >> 1;
if (getsum(_l, mid) >= 1LL * x) r = mid;
else l = mid + 1;
}
res[p] = l - p + 1;
to[0][p] = l + 1;
while (to[0][p] > n) to[0][p] -= n;
}
void mian() {
scanf("%d%d%d", &n, &q, &x);
for (int i = 1; i <= n; i++)
scanf("%d", a + i), sum[i] = sum[i - 1] + a[i];
for (int i = n; i >= 1; i--)
sum2[i] = sum2[i + 1] + a[i];
for (int i = 1; i <= n; i++)
count(i);
for (int j = 1; j <= K; j++)
for (int i = 1; i <= n; i++)
to[j][i] = to[j - 1][to[j - 1][i]];
while (q--) {
ll k; scanf("%lld", &k);
k--;
int now = 1;
for (int i = K; ~i; i--)
if (k - (1LL << i) >= 0)
now = to[i][now], k -= (1LL << i);
printf("%d\n", res[now]);
}
}

G

枚举 1i<jnai,j=1,考虑有多少个 k 满足 ai,k=aj,k=1 都有边。

发现这个东西就是 |SiSj|,其中 Si 表示满足 j>i,ai,j=1j 的集合,于是可以用 std::bitset 处理。

代码
const int N = 3000;
int n;
int a[N + 10][N + 10];
bitset<N + 10> S[N + 10];
void mian() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int x; scanf("%1d", &x);
a[i][j] = x;
if (j > i) S[i].set(j, x);
}
}
ll ans = 0;
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
if (a[i][j]) ans += (S[i] & S[j]).count();
printf("%lld\n", ans);
}
posted @   registerGen  阅读(252)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示