AtCoder ABC 367题解

前言

本题解部分思路来自于网络,仅供参考。

A - Shout Everyday

题目大意

给定 Takahashi 每天的睡觉时间和起床时间,求 Takahashi 在 \(A\) 时是睡着的还是清醒的。

解题思路

根据题意模拟即可。

code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int a,b,c;
    cin >> a >> b >> c;
    if(b >= c) { //如果睡到了第二天
        c += 24;
    }
    if((b <= a && a <= c) | (b <= a + 24 && a + 24 <= c)) {
        printf("No\n");
    } else {
        printf("Yes\n");
    }
    return 0;
}

B - Cut .0

题目大意

给定一个有三位小数的浮点数,输出这个浮点数去除多余的 \(0\) 和小数点后的数。

解题思路

直接输入这个数再输出即可。

code

#include <bits/stdc++.h>
using namespace std;
int main() {
    double x;
    scanf("%lf", &x);
    printf("%g\n", x);
    return 0;
}

C - Enumerate Sequences

题目大意

给定一个序列 \(R\) ,按字典序所有长度为 \(K\) 的,满足以下两个条件的数列:

  1. 数列的第 \(i\) 个元素在 \([1,R_i]\) 之间。
  2. 数列和是 \(K\) 的倍数。

解题思路

直接用dfs枚举即可。

code

#include <bits/stdc++.h>
using namespace std;
int r[15];
int ans[15];
int n, k;
void print() {
    for (int i = 1; i <= n; i++) {
        printf("%d ", ans[i]);
    }
    puts("");
}
void dfs(int ind, int sum) {
    if (ind == n + 1) {
        if (sum % k == 0) {
            print();
        }
        return;
    }
    for (int i = 1; i <= r[ind]; i++) {
        ans[ind] = i;
        dfs(ind + 1, sum + i);
    }
}
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%d", r + i);
    }
    dfs(1, 0);
    return 0;
}

D - Pedometer

题目大意

给出湖边 \(N\) 个休息区中从一个休息区顺时针走到下一个休息区需要走的步数,求满足休息区 \(s\) 顺时针走到休息区 \(t\) 需要走的步数为 \(M\) 的倍数,\((s,t)\) 对的个数。

解题思路

因为湖边 \(N\) 个休息区在一个环上,考虑把输入的数组复制一遍,即把 \([2,1,4,3]\) 变成 \([2,1,4,3,2,1,4,3]\)

为了快速求出两个休息区之间的距离,我们对复制过后的数组做前缀和,前缀和过后得到数组 \(s\)

为了快速得出哪些区间的区间和是 \(M\) 的倍数,我们进行分析。如果区间 \([i,j]\) 的区间和是 \(M\) 的倍数,即 \((s_j - s_{i - 1})\bmod M=0\) ,则:

\[\because (s_j - s_{i - 1}) \bmod M = 0 \\ \therefore s_j - s_{i - 1} \equiv 0 \pmod{M} \\ \therefore s_j \equiv s_{i - 1} \pmod{M} \]

所以,当 \(s_j \equiv s_{i - 1} \pmod{M}\) 时,区间 \([i,j]\) 的区间和为 \(M\) 的倍数。为了得出与 \(s_i\) 同模的数,我们维护一个 \(map\)\(map[i]\) 表示有多少个 \(s_j\) 满足 \(s_j \bmod M = i\) 。每处理一个 \(s_i\) ,答案就增加 \(map[s_i \bmod M]\) ,并把 \(s_i\) 加入 \(map\) 。为了保证不会出现自己走到自己的情况,还需要弹出 \(s_{i - N + 1}\)

code

#include <bits/stdc++.h>
using namespace std;
int a[400005];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        a[i + n] = a[i];
    }
    for (int i = 1; i <= 2 * n; i++) {
        a[i] += a[i - 1];
        a[i] %= m;
    }
    unordered_map<int, int> cnt;
    long long res = 0;
    for (int i = 2; i <= n; i++) cnt[a[i]]++;
    for (int i = n + 1; i <= 2 * n; i++) {
        res += cnt[a[i]];
        cnt[a[i]]++;
        cnt[a[i - n + 1]]--;
    }
    printf("%lld\n", res);
    return 0;
}

E - Permute K times

题目大意

给定两个数组 \(A\)\(X\) ,一个整数 \(K\) ,求 \(A\) 在进行了 \(K\) 次操作

\[A_i = A_{X_i} \]

以后变成了什么。

解题思路

这道题可以看作一道图论题。

\(A\) 数组的每一位可以看作图的节点,\(X\) 数组的每一位可以看作图的边。

下面是由输入数据:

7 3
5 2 6 3 1 4 6
1 2 3 5 7 9 1

生成的图:

而每一次操作都可以看作是点在图上的运动。

为了快速求出每一个点在运动了 \(K\) 步后到了哪里,我们维护一个倍增数组 \(x[i][j]\) 表示哪一个节点走了 \(2^j\) 步后到了第 \(i\) 位。在处理第 \(i\) 个位置时,定义一个变量 \(p\) ,遍历 \(K\) 的每一个二进制位,如果 \(K\) 的二进制第 \(j\) 位为 \(1\) ,则 \(p\) 移动到第 \(x[i][j]\) 位上,最后把 \(p\) 节点移动到第 \(i\) 位上。

code

#include <bits/stdc++.h>
using namespace std;
int a[200005];
int x[200005][64];
int main() {
    int n;
    long long k;
    scanf("%d%lld", &n, &k);
    for (int i = 1, t; i <= n; i++) {
        scanf("%d", &t);
        x[i][0] = t;
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
    }
    for (int i = 1; i <= 60; i++) {
        for (int j = 1; j <= n; j++) {
            x[j][i] = x[x[j][i - 1]][i - 1];
        }
    }
    for (int i = 1; i <= n; i++) {
        int p = i;
        for (int j = 60; j >= 0; j--) {
            if (k >> j & 1) p = x[p][j];
        }
        printf("%d ", a[p]);
    }
    puts("");
    return 0;
}

F - Rearrange Query

题目大意

给定两个数组 \(A\)\(B\) ,对于每一次询问 \(l_i,\ r_i,\ L_i,\ R_i\) ,回答可不可以通过排列 \(A[l_i...r_i]\) 使得 \(A[l_i...r_i] = B[L_i...R_i]\)

解题思路

这道题先求出每一个数的哈希,再对这些哈希求前缀和以求出区间的哈希。对于每一次询问,如果两个区间哈希值相同就输出 Yes 否则输出 No

code

#include <bits/stdc++.h>
#define MOD 156876589475701
#define MAX_N 200005
using namespace std;
int a[MAX_N], h[MAX_N], b[MAX_N], ph1[MAX_N], ph2[MAX_N];
int main() {
    int n, q;
    scanf("%d%d", &n, &q);
    mt19937_64 mt(time(0));
    for (int i = 1; i <= n; i++) {
        h[i] = mt();
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        ph1[i] = (h[a[i]] + ph1[i - 1]) % MOD;
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", b + i);
        ph2[i] = (h[b[i]] + ph2[i - 1]) % MOD;
    }
    int l, r, L, R;
    while (q--) {
        scanf("%d%d%d%d", &l, &r, &L, &R);
        if (ph1[r] - ph1[l - 1] == ph2[R] - ph2[L - 1]) {
            puts("Yes");
        } else {
            puts("No");
        }
    }
    return 0;
}
posted @ 2024-08-20 14:01  sxl701817  阅读(103)  评论(0)    收藏  举报