AtCoder ABC 367題解

sxl701817發表於2024-08-20

前言

本題解部分思路來自於網路,僅供參考。

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](E - Permute K times (atcoder.jp))

題目大意

給定兩個陣列 $A$ 和 $X$ 和一個整數 $K$ ,求 $A$ 在進行了 $K$ 次操作

$$ A_i = A_{X_i} $$

以後變成了什麼。

解題思路

這道題可以看作一道圖論題。

$A$ 陣列的每一位可以看作圖的節點,$K$ 陣列的每一位可以看作圖的邊。

而每一次操作都可以看作是點在圖上的運動。

為了快速求出每一個點在運動了 $K$ 步後到了哪裡,我們維護一個倍增陣列 $x[i][j]$ 表示第 $i$ 個點走了 $2^j$ 步後到了哪裡。之後用倍增陣列求出每一個點在進行了 $K$ 次操作之後到了哪裡,最後輸出結果。

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]$ 。

解題思路

這道題直接使用雜湊+字首和即可。

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;
}

相關文章