NOIP 2023 比赛报告

第一题

比赛情况

\(100\) 分,耗时 \(1\) 小时。

题解

对于 \(1\le i\le n\) ,比较 \(w_i\) 字典序最小的字符 \(a_i\) 与每个 \(w_j(i\ne j)\) 字典序最大的字符 \(b_j\) 。如果有 \(b_j\le a_i\) ,则 \(w_i\) 不能成为字典序最小的单词,反之可以。

代码

点击查看代码
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 3005, M = 3005;
int n, m;
char s[N][M], mx[N], mn[N];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    memset(mx, 0, sizeof(mx));
    memset(mn, 0x7f, sizeof(mn));
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> s[i];
        for (int j = 0; j < m; j++) {
            mx[i] = max(mx[i], s[i][j]);
            mn[i] = min(mn[i], s[i][j]);
        }
    }
    for (int i = 0; i < n; i++) {
        bool flag = true;
        for (int j = 0; j < n; j++) {
            if (i == j)
                continue;
            if (mn[i] >= mx[j]) {
                flag = false;
                break;
            }
        }
        if (flag)
            cout << "1";
        else
            cout << "0";
    }
    return 0;
}

第二题

比赛情况

\(100\) 分,耗时 \(2\) 小时。

题解

对于每个变量,记录为与其他变量初值的关系或者为某个定值。

建立一个无向图,当变量 \(i\) 为变量 \(j\) 的初值时,连接 \(i,j\) ,边权为 \(0\) ;当变量 \(i\) 为变量 \(j\) 的初值的非时,连接 \(i,j\) ,边权为 \(1\)

对图进行 DFS,如果一个环总共的边权和为奇数或有一个点对应变量为定值 \(U\) ,则整个连通分量中的点对应的变量的初值应为 \(U\)

代码

点击查看代码
#include <iostream>
using namespace std;
const int N = 1e5 + 5, M = 1e5 + 5;
int C, T;
int n, m, x[N], y[N];
struct Edge {
    int v, w, next;
} edge[M << 1];
int head[N], cnt = 0;
void addedge(int u, int v, int w) {
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
int fa[N];
int find(int x) { return fa[x] = (x == fa[x] ? x : find(fa[x])); }
void merge(int x, int y) {
    int fx = find(x), fy = find(y);
    fa[fx] = fy;
}
int val[N], unk[N];
void dfs(int u, int fa) {
    int g = find(u);
    if (unk[g])
        return;
    for (int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].v, w = edge[i].w * val[u];
        if (v == fa)
            continue;
        if (val[v]) {
            if (val[v] != w) {
                unk[g] = 1;
                return;
            }
            continue;
        }
        val[v] = w;
        dfs(v, u);
        if (unk[g])
            return;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> C >> T;
    while (T--) {
        cnt = 0;
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            x[i] = 1, y[i] = i, head[i] = -1, val[i] = unk[i] = 0, fa[i] = i;
        while (m--) {
            char s[5], op;
            cin >> s;
            op = s[0];
            if (op == 'T') {
                int i;
                cin >> i;
                x[i] = 0, y[i] = 1;
            } else if (op == 'F') {
                int i;
                cin >> i;
                x[i] = 0, y[i] = -1;
            } else if (op == '+') {
                int i, j;
                cin >> i >> j;
                x[i] = x[j], y[i] = y[j];
            } else if (op == '-') {
                int i, j;
                cin >> i >> j;
                x[i] = x[j], y[i] = -y[j];
            } else {
                int i;
                cin >> i;
                x[i] = 0, y[i] = 0;
            }
        }
        for (int i = 1; i <= n; i++) {
            if (x[i]) {
                int u = i, v, w;
                if (y[i] > 0)
                    v = y[i], w = 1;
                else
                    v = -y[i], w = -1;
                addedge(u, v, w);
                addedge(v, u, w);
                merge(u, v);
            }
        }
        for (int i = 1; i <= n; i++)
            if (!x[i])
                unk[find(i)] = (y[i] ? -1 : 1);
        for (int i = 1; i <= n; i++) {
            int g = find(i);
            if (x[i] && !unk[g]) {
                val[i] = 1;
                dfs(i, 0);
                if (!unk[g])
                    unk[g] = -1;
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
            if (unk[find(i)] == 1)
                ans++;
        cout << ans << endl;
    }
    return 0;
}

第三题

比赛情况

没做。

题解

可以看做可以从 \((x,y)\) 走到 \((x+1,y),(x,y+1),(x+1,y+1)\) ,要求 \((1,1)\) 走到 \((n,m)\) 并且对所有经过的点 \((x,y)\) 都有 \(a_x<b_y\)\(a_x>b_y\)

分析当 \(a_x<b_y\) 的情况,另一种情况同理。

对于序列 \(a_{1\dots i}\)\(b_{1\dots j}\) 来说,如果 \(a_{\min}<b_{\min}\) ,那么 \(a_{\min}\) 所在行都合法,否则不合法;如果 \(a_{\max}<b_{\max}\) ,那么 \(b_{\max}\) 所在列都合法,否则不合法。接下来再分析左上角和右下角的情况,如此递归下去。

代码

第四题

比赛情况

DP 没写出来。

题解

\(f_i\) 为前 \(i\) 天内,第 \(i\) 天没跑的能量值。

所以 \(f_i=\max\{f_{i-1},\max\limits_{j=i-k-1}^{i-1}[f_j-(i-j-1)d+val(j+1,i-1)]\}\) ,其中 \(val(L,R)=\sum\limits_i^{L\le l_i\le r_i\le R}v_i\)

可以发现我们只需要 \(f_{l_i-1}\)\(f_{r_i+1}\) 的值,线段树优化即可。

代码

posted @ 2023-11-25 18:36  01bit  阅读(41)  评论(0编辑  收藏  举报