ABC378合集

bryce_yyds發表於2024-11-04

A - Pairing

思路

排個序,比較相鄰元素。

程式碼

#include<iostream>
#include<algorithm>

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}

int a[5], ans;

int main(){
    a[1] = read(), a[2] = read(), a[3] = read(), a[4] = read();
    sort(a + 1, a + 5);
    for (int i = 1; i <= 4; i++){
        if (a[i] == a[i + 1]) i++, ans++;
    }
    cout << ans;
    return 0;
}

B - Garbage Collection

思路

\(x\) 表示 \(d\mod q_t\) 的結果,那麼 \(x\le r_t\),答案就為 \(d + r_t - x\),否則答案就為 \(d + q_t + r_t - x\)

程式碼

#include<iostream>
#define int long long

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}

const int N = 110;
int n, m;
int q[N], r[N];

signed main(){
    n = read();
    for (int i = 1; i <= n; i++) q[i] = read(), r[i] = read();
    m = read();
    for (int i = 1; i <= m; i++){
        int t = read(), d = read(), x = d % q[t];
        if (r[t] - x < 0) cout << d + (r[t] + q[t] - x) << '\n';
        else cout << d + (r[t] - x) << '\n';
    }
    return 0;
}

C - Repeating

思路

\(q_{a_i}\) 表示 \(a_i\) 在當前掃描的字首裡出現最後的位置,如果遇到 \(a_i\) 輸出 \(q_{a_i}\),然後將 \(q_{a_i}\) 更新為 \(i\),由於 \(a_i\) 太大,用個 map 即可。

程式碼

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}

const int N = 2e5 + 10;
int n;
int a[N];
map<int, int> q;

signed main(){
    n = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i <= n; i++){
        cout << (q[a[i]] == 0 ? -1 : q[a[i]]) << ' ';
        q[a[i]] = i;
    }
    return 0;
}

D - Count Simple Paths

思路

對於每一個點作為起點進行深搜,若找到了長度為 \(k\) 的路徑,答案加 \(1\),在搜尋一次路徑時要打上標記,防止走迴路,搜尋完一個路徑後要回溯,清空標記。

程式碼

#include<iostream>
#define int long long

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}

const int N = 15;
int n, m, k, dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1}, ans;
bool a[N][N], vis[N][N];
void dfs(int x, int y, int sum){
    if (vis[x][y]) return;
    if (sum == k){
        ans++;
        return;
    }
    vis[x][y] = 1;
    for (int i = 0; i < 4; i++){
        int nx = x + dx[i], ny = y + dy[i];
        if (nx < 1 || nx > n || ny < 1 || ny > m || !a[nx][ny]) continue;
        dfs(nx, ny, sum + 1);
    }
    vis[x][y] = 0;
}

signed main(){
    n = read(), m = read(), k = read();
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            char c; cin >> c;
            if (c == '.') a[i][j] = 1;
        }
    }
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            if (a[i][j]) dfs(i, j, 0);
        }
    }
    cout << ans;
    return 0;
}

E - Mod Sigma Problem

思路

將題目要求的東西轉化一下,轉化為求以下的式子:

\[\sum\limits_{1\le l\le r\le n} (sum_r - sum_{l - 1})\mod m \]

其中 \(sum_i\) 表示 \(1\)\(i\) 之間的 \(a_i\) 的和,即字首和。

由於有一個模 \(m\),不好做,嘗試再轉化一下:

\[\sum\limits_{1\le l\le r\le n} ((sum_r\mod m) - (sum_{l - 1}\mod m)) \]

但是這一步的轉化是錯的,因為 \(sum_r\mod m\) 可能比 \(sum_{l - 1}\mod m\) 小,相減會出現負數,而原來的計算不會出現負數,這時答案要加上一個 \(m\),所以對於一個 \(r\),在 \(0\le l - 1\lt r\) 中,大於 \(sum_r\mod m\)\(sum_{l - 1}\mod m\) 計算時都要加上 \(m\),用樹狀陣列統計有多少個這樣的 \(l - 1\),記為 \(X_r\),即為加上總的 \(m\) 的個數。對每個 \(sum_i\) 先對 \(m\) 取模,於是式子變成這樣:

\[\sum\limits_{1\le r\le n} (sum_r\times r - \sum\limits_{1\le l\le r} sum_{l - 1} + X_r\times m) \]

其中,\(\sum\limits_{1\le l\le r} sum_{l - 1}\) 可以直接求,\(X_r\) 用樹狀陣列求。

程式碼

#include<iostream>
#define int long long

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}

const int N = 2e5 + 10;
int n, m, ans;
int a[N], sum[N];
int t[N];
int lowbit(int x){
    return x & -x;
}
void add(int x, int k){
    for (int i = x; i <= m; i += lowbit(i)) t[i] += k;
}
int query(int x){
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += t[i];
    return res;
}

signed main(){
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i <= n; i++) sum[i] = (sum[i - 1] + a[i]) % m;
    int res = 0;
    for (int i = 1; i <= n; i++){
        ans += sum[i] * i - res + m * (query(m) - query(sum[i] + 1));
        res += sum[i];
        add(sum[i] + 1, 1);
    }
    cout << ans;
    return 0;
}

F - Add One Edge 2

思路

題目要求連邊後這個環的所有點的度數為 \(3\),那麼連線的這兩個點的度數一定為 \(2\),其它環上的點的度數都為 \(3\),那麼在一個度數為 \(3\) 的點開始遍歷,找到連續的度數為 \(3\) 的點,直到找不了,於是這些度數為 \(3\) 的點相互連通,它們上面連線的度數為 \(2\) 的點任意兩兩連線都能形成一個符合題目要求的環,設這個連通的度數為 \(3\) 的點上面的度數為 \(2\) 的點的個數為 \(m\),那麼答案加上 \(\frac{m\times (m - 1)}{2}\)

程式碼

#include<iostream>
#define int long long

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}

const int N = 2e5 + 10;
int n, res, ans;
struct edge{
    int v, nxt;
}e[N << 1];
int head[N], cnt;
int in[N];
void add(int u, int v){
    e[++cnt] = (edge){v, head[u]};
    head[u] = cnt;
}
bool vis[N];
void solve(int u){
    vis[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt){
        int v = e[i].v;
        if (vis[v]) continue;
        if (in[v] == 3){
            solve(v);
        }
    }
    for (int i = head[u]; i; i = e[i].nxt){
        int v = e[i].v;
        if (!vis[v] && in[v] == 2) res++;
    }
}

signed main(){
    n = read();
    for (int i = 1; i < n; i++){
        int u = read(), v = read();
        add(u, v), add(v, u);
        in[u]++, in[v]++;
    }
    for (int i = 1; i <= n; i++){
        if (in[i] == 3 && !vis[i]){
            res = 0;
            solve(i);
            ans += res * (res - 1) / 2;
        }
    }
    cout << ans;
    return 0;
}