Atcoder Beginner Contest 425

A

按照题意计算即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;

signed main() {
    int n, ans = 0;
    scanf ("%lld", &n);
    for (int i = 1; i <= n; i++)
        ans += ((i & 1) ? -1 : 1) * i * i * i;
    printf ("%lld\n", ans);
    return 0;
}

B

开桶计出现次数看有没有出现多次的即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;

int N, idx;
int a[15], ton[15], num[15];

signed main() {
    scanf ("%lld", &N);
    for (int i = 1; i <= N; i++) {
        scanf ("%lld", &a[i]);
        if (~a[i]) ton[a[i]]++;
    }
    for (int i = 1; i <= N; i++) {
        if (ton[i] > 1) {
            printf ("No\n");
            return 0;
        }
    }
    for (int i = 1; i <= N; i++) {
        if (!ton[i]) num[++idx] = i;
    }
    printf ("Yes\n");
    for (int i = 1, j = 1; i <= N; i++) {
        if (~a[i]) 
            printf ("%lld ", a[i]);
        else 
            printf ("%lld ", num[j++]);
    }
    return 0;
}

C

既然是头移到尾,考虑直接复制一份 \(a\) 数组,同时计前缀和。那么只需要维护序列开头的位置即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 2e5 + 10;
int N, Q;
int a[maxn << 1], sum[maxn << 1], head;

signed main() {
    scanf ("%lld", &N);
    scanf ("%lld", &Q);
    for (int i = 1; i <= N; i++) 
        scanf ("%lld", &a[i]), a[i + N] = a[i];
    for (int i = 1; i <= N * 2; i++)
        sum[i] = sum[i - 1] + a[i];
    head = 0;
    for (int _ = 1; _ <= Q; _++) {
        int opt;
        scanf ("%lld", &opt);
        if (opt == 1) {
            int c;
            scanf ("%lld", &c);
            head = (head + c) % N;
        }
        if (opt == 2) {
            int l, r;
            scanf ("%lld %lld", &l, &r);
            printf ("%lld\n", sum[head + r] - sum[head + l - 1]);
        }
    }
    return 0;
}

D

感觉遇到过。很经典的扩散问题啊。

直接考虑从黑点 bfs,但是要注意每次更新不能直接更新遍历到的新点,而是一轮过后统一更新,不然会影响到其他点的判断。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 3e5 + 10;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
int H, W;
char str[maxn];
queue<pair<int,int>> q, upd;

signed main() {
    scanf ("%lld", &H);
    scanf ("%lld", &W);
    int mat[H + 5][W + 5] = {};
    bool vis[H + 5][W + 5] = {};
    memset (vis, false, sizeof(vis));
    for (int i = 1; i <= H; i++) {
        scanf ("%s", str + 1);
        for (int j = 1; j <= W; j++) {
            if (str[j] == '#') mat[i][j] = 1;
            else mat[i][j] = 0;
        }
    }
    for (int i = 1; i <= H; i++) {
        for (int j = 1; j <= W; j++) {
            if (mat[i][j]) 
                q.push(make_pair(i, j));
        }
    }
    for (int _ = 1; ; _++) {
        while (!q.empty()) {
            auto t = q.front();
            q.pop();

            int x = t.first, y = t.second;
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i], ny = y + dy[i];
                if (nx < 1 || nx > H || ny < 1 || ny > W) continue;
                if (mat[nx + 1][ny] + mat[nx][ny + 1] + mat[nx - 1][ny] + mat[nx][ny - 1] == 1 && !mat[nx][ny]) upd.push(make_pair(nx, ny));
                // vis[nx][ny] = true;
            }
        }

        if (upd.empty()) break;
        while (!upd.empty()) {
            auto t = upd.front();
            upd.pop();
            mat[t.first][t.second] = 1;
            q.push(make_pair(t.first, t.second));
        }
    }
    int sum = 0;
    for (int i = 1; i <= H; i++) {
        for (int j = 1; j <= W; j++)
            sum += mat[i][j];
    }
    printf ("%lld\n", sum);
    return 0;
}

E

第一反应是组合数学,因为 \(C_i\) 个对应的同一个数比较明显的。每次从剩余空位中选即可。记 \(sum = \sum\limits_{i=1}^{n}{C_i}\),答案 \(\prod\limits_{i=1}^{n}{\binom{sum - \sum\limits_{j=1}^{i-1}{C_i}}{C_i}}\)

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 3e5 + 10;
int Test, mod;
int N, c[maxn], sum[maxn];
int combine[5005][5005];

void init() {
    combine[0][0] = 1;
    for (int i = 1; i <= 5000; i++) {
        combine[i][0] = 1;
        for (int j = 1; j <= 5000; j++)
            combine[i][j] = (combine[i - 1][j - 1] + combine[i - 1][j]) % mod;
    }
}

void sol() {
    cin >> N;
    for (int i = 1; i <= N; i++)
        cin >> c[i], sum[i] = sum[i - 1] + c[i];
    int ans = 1;
    for (int i = 1; i <= N; i++)
        ans = (ans * combine[sum[N] - sum[i - 1]][c[i]]) % mod;
    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin >> Test >> mod;
    init();
    while (Test--) sol();
    return 0;
}

F

\(N \leq 22\),考虑状压。添加不好做,正难则反看做删除的方案数。

\(f_S\) 表示已经删除的集合,则有转移:\(f_{S \mid 2^i} \leftarrow f_{S \mid 2 ^i} + f_{S}\)。但是值得注意的,对于相邻的相同字符 \(s_i,s_j\),删除了 \(s_i\)\(s_j\) 的结果一样,直接算会算重贡献。每次删除的相邻两个不同时才可转移。

答案即为 \(f_{2^N - 1}\)

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int mod = 998244353;
int N;
char s[25];
int f[1 << 25];

signed main() {
    scanf ("%lld %s", &N, s);
    f[0] = 1;
    for (int st = 0; st < (1 << N); st++) {
        char ch = '#';
        for (int i = 0; i < N; i++) {
            if (!((st >> i) & 1)) {
                if (ch != s[i]) 
                    f[st | (1 << i)] = (f[st | (1 << i)] + f[st]) % mod;
                ch = s[i];
            }
        }
    }
    printf ("%lld\n", f[(1 << N) - 1]);
    return 0;
}
posted @ 2025-10-13 21:08  xAlec  阅读(4)  评论(0)    收藏  举报