2025.8.17模拟赛

T1

有个 \(n\times m\) 的矩阵,行编号为 \(0\dots n−1\),列编号为 \(0\dots m−1\),第 \(i\) 行第 \(j\) 列一开始为 \(im+j\)
现在支持三种操作:交换两行,交换两列,或者交换某两个位置。求进行完 \(q\) 次操作后矩阵的形态。
\(1\le n,m\le 5000,1\le q\le 10^6\)

每行初始定义一个 \(X_i=i\),每列初始定义一个 \(Y_i=i\),交换行列直接交换 \(X\)\(Y\) 即可。

再初始一个 \(a_{i,j}=im+j\),然后交换两点就是交换 \(a_{X_{x_1},Y_{y_1}},a_{X_{x_2},Y_{y_2}}\)

原题是一个 seed 和压缩输出。

赛时代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5005, M = 1e6 + 5, P = 998244353;
uint64_t seed;
uint64_t next() {
    seed ^= seed << 13;
    seed ^= seed >> 7;
    seed ^= seed << 17;
    return seed;
}
string s;
int n, m, q;
int a[N], b[N], c[N][N];
int p17[N], p19[N], ans;
int signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> m >> q >> seed >> s;
    p17[0] = p19[0] = 1;
    for (int i = 0; i < n; ++i)
        a[i] = i;
    for (int i = 0; i < m; ++i)
        b[i] = i;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            c[i][j] = i * m + j;
    for (int i = 1; i < N; ++i)
        p17[i] = 17ll * p17[i - 1] % P, p19[i] = 19ll * p19[i - 1] % P;
    for (int i = 0, r1, c1, r2, c2; i < q; ++i) {
        if (s[i] == 'r')
            r1 = next() % n, r2 = next() % n, swap(a[r1], a[r2]);
        if (s[i] == 'c')
            c1 = next() % m, c2 = next() % m, swap(b[c1], b[c2]);
        if (s[i] == 'f') {
            r1 = next() % n, c1 = next() % m;
            r2 = next() % n, c2 = next() % m;
            swap(c[a[r1]][b[c1]], c[a[r2]][b[c2]]);
        }
    }
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            ans = (1ll * p17[i] * p19[j] % P * c[a[i]][b[j]] % P + ans) % P;
    cout << ans << '\n';
    return 0;
}

T2

\(n\) 个砝码,根据材质不同质量只有 1g,2g,3g 三种。
现在砝码上的质量标签都遗失了,由于只有材质不同,从外表难以分辨。但所幸还有一个天平,可以用这个天平秤量砝码之间的重量关系。
某些砝码之间的重量关系已经称出来了,但其它的还不知道。
现在已经选了砝码 \(a,b\) 两个放在了天平左边,想再选另外两个放在右边,求有多少种选法使得由已知信息能确定左边更重/相等/右边更重。
\(1\le n\le 50\)

只有 \(50\) 岂不是乱搞?

直接枚举右边的两颗,以及 \(4\) 颗砝码的质量。

我们对于所有相等的关系直接将其缩成一个点,对于所有 \(u<v\)\(u\)\(v\) 连一条有向边。

然后将只有出度的点设为 \(1\),只有入度的设为 \(3\),其余为 \(2\),这样一定不劣。

然后检查一下是否合法即可。

赛时代码
#include <bits/stdc++.h>
using namespace std;
const int N = 53;
int n, fa[N], id[N];
int in[N], out[N], I, J;
int A[N], B[N];
int ans1, ans2, ans3;
char s[N][N];
int find(int x) {
    if (fa[x] == x)
        return fa[x];
    return fa[x] = find(fa[x]);
}
void merge(int x, int y) {
    if ((x = find(x)) != (y = find(y)))
        fa[x] = y;
}
void add(int u, int v) { ++out[u], ++in[v]; }
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> s[i] + 1, fa[i] = i;
    cin >> I >> J;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (s[i][j] == '=')
                merge(i, j);
    for (int i = 1; i <= n; ++i)
        id[i] = find(i);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (s[i][j] == '-')
                add(id[i], id[j]);
    for (int i = 1; i <= n; ++i) {
        if (!in[id[i]])
            A[id[i]] = 1;
        else if (in[id[i]] && out[id[i]])
            A[id[i]] = 2;
        else
            A[id[i]] = 3;
    }
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) {
            int s1 = 0, s2 = 0, s3 = 0;
            if (I == i || I == j || J == i || J == j || i == j)
                continue;
            for (int a = 1; a <= 3; ++a)
                for (int b = 1; b <= 3; ++b) {
                    if (id[I] == id[J] && a != b)
                        continue;
                    for (int c = 1; c <= 3; ++c) {
                        if (id[I] == id[i] && a != c)
                            continue;
                        if (id[J] == id[i] && b != c)
                            continue;
                        for (int d = 1; d <= 3; ++d) {
                            if (id[I] == id[j] && a != d)
                                continue;
                            if (id[J] == id[j] && b != d)
                                continue;
                            if (id[i] == id[j] && c != d)
                                continue;
                            for (int l = 1; l <= n; ++l)
                                B[l] = A[l];
                            B[id[I]] = a, B[id[J]] = b;
                            B[id[i]] = c, B[id[j]] = d;
                            bool fl = 1;
                            for (int k = 1; k <= n; ++k)
                                for (int l = 1; l <= n; ++l) {
                                    if (s[k][l] == '-' && B[id[k]] >= B[id[l]])
                                        fl = 0;
                                }
                            if (fl) {
                                if (a + b > c + d)
                                    ++s1;
                                if (a + b == c + d)
                                    ++s2;
                                if (a + b < c + d)
                                    ++s3;
                            }
                        }
                    }
                }
            if ((s1 && s2) || (s1 && s3) || (s2 && s3))
                continue;
            ans1 += (s1 > 0), ans2 += (s2 > 0), ans3 += (s3 > 0);
        }
    cout << ans1 / 2 << '\n' << ans2 / 2 << '\n' << ans3 / 2 << '\n';
    return 0;
}

T3

一条路从 \((1,0)\)\((n,0)\),店铺排列在 \((i,1)\)\((i,-1)\) 的位置(\(1\le i\le n\))。\((i,1)\) 的位置有 \(a_i\) 的顾客,\((i,-1)\)\(b_i\) 的顾客。
可以选择一些店铺贴上广告,一家店 \((x,y)\) 里的顾客能看到广告的条件为 \((x,y)\) 没贴广告,且存在 \(|x'-x|\le d\) 使得 \((x',-y)\) 贴了广告。求能从店里看到广告的顾客数的最大值。
\(1\le n\le 1500\)

如果一个店的人看不到广告,那么将其贴上广告肯定是不劣的。

所以在 \((x,y)\) 贴广告相当于花费 \(a_i\)\(b_i\) 的代价,覆盖 \((x,y)\)\((x+z,-y)(-d\le z\le d)\),求最小覆盖代价。

然后 \(dp_{i,j}\) 表示上一列覆盖到 \(i\)\(i+1\) 未覆盖,下一列覆盖到 \(j\)\(j+1\) 未覆盖。当然 \(i+2\)\(j+2\) 之后的有可能被盖,不将其计入不会影响最优性。

再枚举选哪个,考虑最远伸展到哪,就可以实现 \(n^3\)

赛时实现较为野蛮。

80pts代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1505;
int n, d, a[N], b[N];
int sum, L, M, R;
int dp[N][N];
void Min(int &x, int y) { x = min(x, y); }
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    memset(dp, 0x3f, sizeof(dp));
    cin >> n >> d;
    for (int i = 1; i <= n; ++i)
        cin >> a[i], sum += a[i];
    for (int i = 1; i <= n; ++i)
        cin >> b[i], sum += b[i];
    dp[0][0] = 0;
    for (int i = 0; i <= n; ++i) {
        for (int j = 0; j <= n; ++j) {
            L = max(j - d + 1, 1), R = min(j + d + 1, n), M = min(R, n - d);
            for (int k = L; k <= M; ++k)
                Min(dp[i][k + d], dp[i][j] + a[k]);
            for (int k = M + 1; k <= R; ++k)
                Min(dp[i][n], dp[i][j] + a[k]);
            if (i < n && i <= j + d)
                Min(dp[i + 1][min(n, max(j, i + d + 1))], dp[i][j] + a[i + 1]);

            L = max(i - d + 1, 1), R = min(i + d + 1, n), M = min(R, n - d);
            for (int k = L; k <= M; ++k)
                Min(dp[k + d][j], dp[i][j] + b[k]);
            for (int k = M + 1; k <= R; ++k)
                Min(dp[n][j], dp[i][j] + b[k]);
            if (j < n && j <= i + d)
                Min(dp[min(n, max(i, j + d + 1))][j + 1], dp[i][j] + b[j + 1]);
        }
    }
    cout << sum - dp[n][n] << '\n';
    return 0;
}

然后直接上个什么线段树区间取 \(\min\) 什么的暴力维护,力大砖飞

100pts代码
#include <bits/stdc++.h>
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
#define mid (l + r >> 1)
using namespace std;
const int N = 1505;
int n, d, a[N], b[N];
int sum, L, M, R;
int dp[N][N];
void Min(int &x, int y) { x = min(x, y); }
struct SEG {
    int s[N << 2];
    void build(int p, int l, int r) {
        s[p] = 1e9;
        if (l == r)
            return;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
    }
    void upd(int p, int l, int r, int L, int R, int v) {
        if (L <= l && r <= R)
            return Min(s[p], v);
        if (L <= mid)
            upd(ls(p), l, mid, L, R, v);
        if (mid < R)
            upd(rs(p), mid + 1, r, L, R, v);
    }
    int ask(int p, int l, int r, int x) {
        if (l == r)
            return s[p];
        if (x <= mid)
            return min(s[p], ask(ls(p), l, mid, x));
        else
            return min(s[p], ask(rs(p), mid + 1, r, x));
    }
} x[N], y[N];
struct BIT {
    int s[N << 2];
    void build(int p, int l, int r) {
        s[p] = 1e9;
        if (l == r)
            return;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
    }
    void upd(int p, int l, int r, int x, int y) {
        if (l == r)
            return s[p] = y, void();
        if (x <= mid)
            upd(ls(p), l, mid, x, y);
        else
            upd(rs(p), mid + 1, r, x, y);
        s[p] = min(s[ls(p)], s[rs(p)]);
    }
    int ask(int p, int l, int r, int L, int R) {
        if (L > R)
            return 1e9;
        if (L <= l && r <= R)
            return s[p];
        int res = 1e9;
        if (L <= mid)
            Min(res, ask(ls(p), l, mid, L, R));
        if (mid < R)
            Min(res, ask(rs(p), mid + 1, r, L, R));
        return res;
    }
} X, Y;
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    memset(dp, 0x3f, sizeof(dp));
    cin >> n >> d;
    X.build(1, 1, n), Y.build(1, 1, n);
    for (int i = 1; i <= n; ++i)
        cin >> a[i], sum += a[i], X.upd(1, 1, n, i, a[i]);
    for (int i = 1; i <= n; ++i)
        cin >> b[i], sum += b[i], Y.upd(1, 1, n, i, b[i]);
    dp[0][0] = 0;
    for (int i = 0; i <= n; ++i)
        x[i].build(1, 0, n), y[i].build(1, 0, n);
    for (int i = 0; i <= n; ++i) {
        for (int j = 0; j <= n; ++j) {
            if (j > d)
                Min(dp[i][j], x[i].ask(1, 0, n, j) + a[j - d]);
            if (i > d)
                Min(dp[i][j], y[j].ask(1, 0, n, i) + b[i - d]);
            L = max(j - d + 1, 1), R = min(j + d + 1, n), M = min(R, n - d);
            x[i].upd(1, 0, n, L + d, M + d, dp[i][j]);
            Min(dp[i][n], dp[i][j] + X.ask(1, 1, n, M + 1, R));
            if (i < n && i <= j + d)
                Min(dp[i + 1][min(n, max(j, i + d + 1))], dp[i][j] + a[i + 1]);
            L = max(i - d + 1, 1), R = min(i + d + 1, n), M = min(R, n - d);
            y[j].upd(1, 0, n, L + d, M + d, dp[i][j]);
            Min(dp[n][j], dp[i][j] + Y.ask(1, 1, n, M + 1, R));
            if (j < n && j <= i + d)
                Min(dp[min(n, max(i, j + d + 1))][j + 1], dp[i][j] + b[j + 1]);
        }
    }
    cout << sum - dp[n][n] << '\n';
    return 0;
}

T4

??
纯属大模拟加神秘优化,赛时赛后都没管。

posted @ 2025-08-20 20:03  zzy0618  阅读(17)  评论(0)    收藏  举报