CSP 总结

CSP-J2022

A 乘方

直接把 \(a=1\) 特判掉,开 \(\mathrm{long~long}\) 暴力乘。

void solve() {
    ll s = 1, a, b;
    cin >> a >> b;
    if(a == 1) {
        cout << 1 << endl;
        return;
    }
    REP(i, b) {
        s *= a;
        if(s > 1e9) {
            cout << -1 << endl;
            return;
        }
    }
    cout << s << endl;
}

B 解密

解一个一元二次方程即可。

void solve() {
    ll n, e, d, m;
    cin >> n >> e >> d;
    m = e * d;
    ll B = n - m + 2;
    ll D = B * B - 4 * n;
    ll S = sqrt(D);
    if(D < 0 || S * S != D) {
        cout << "NO" << endl;
        return;
    }
    if(B - S <= 0 || (B - S) % 2) {
        cout << "NO" << endl;
        return;
    }
    cout << (B - S) / 2 << " " << (B + S) / 2 << endl;
}

C 逻辑表达式

性质题。
首先题目中说与运算比或预算优先级高,这个条件可以消除掉。
假如有式子 \(a|b\&c\)
如果 \(a\)\(0\),那么对结果没有影响。
如果 \(a\)\(1\),那么直接短路。
所以优先级不重要。
考虑从头开始扫。
如果有或运算的短路,那么把之后连续的与运算跳过即可。
如果有与运算的短路,就也是把之后连续的与运算跳过。

void solve() {
    int n;
    string s;
    cin >> s; n = s.size();
    int res = 0, A = 0, B = 0, F = 0;
    REP(i, n) {
        if(F) {
            if(s[i] == '(') {
                int cnt = 1;
                while(cnt) {
                    i++;
                    if(s[i] == '(') cnt++;
                    if(s[i] == ')') cnt--;
                }
            }
            else if(F == 1 && s[i] == '|') {
                F = 0;
            }
            else if(s[i] == ')') {
                F = 0;
            }
            else if(F == 1 && s[i] == '&') {
                A++;
            }
            else if(F == 2 && s[i] == '|') {
                B++;
            }
        }
        else {
            if(s[i] == '1') res = 1;
            if(s[i] == '0') res = 0;
            if(s[i] == '&' && !res) {
                F = 1;
                A++;
            }
            if(s[i] == '|' && res) {
                F = 2;
                B++;
            }
        }
    }
    cout << res << endl << A << " " << B << endl; 
}

D 上升点列

设置状态 \(f_{i, j}\) 为第 \(i\) 个点为连线终点,还剩 \(j\) 个自由点可以用的最长长度。
直接 \(O(n^2k)\) 转移即可。

void solve() {
    int n, k;
    cin >> n >> k;
    vector<PII> a(n);
    REP(i, n) cin >> FI(a[i]) >> SE(a[i]);
    sort(ALL(a));
    vector<vector<int>> f(n, vector<int>(k + 1));
    REP(i, n) {
        f[i][k] = 1;
        REP(j, i) {
            if(SE(a[j]) <= SE(a[i])) {
                int len = SE(a[i]) - SE(a[j]) + FI(a[i]) - FI(a[j]) - 1;
                FOR(l, 0, k) {
                    int r = l + len;
                    if(r > k) break;
                    chmax(f[i][l], f[j][r] + len + 1);
                }
            }
        }
    }
    int ans = 0;
    REP(i, n) {
        FOR(j, 0, k) {
            chmax(ans, f[i][j] + j);
        }
    }
    cout << ans << endl;
}

CSP-S2022

A 假期计划

首先 \(\mathrm{bfs}\) \(O(n_2)\) 算出每两个点之间的距离。
随后考虑先经过两个点的情况,在合并成四个点的。
但是会发现可能两个不同的点经过值最大的点可能是相同的,
为了避免这种问题,直接记录最大值,次大值,次次大值即可。

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    vector<ll> a(n);
    FOR(i, 1, n - 1) cin >> a[i];
    vector<vector<int>> e(n);
    REP(i, m) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    vector<vector<int>> d(n, vector<int>(n, INF));
    REP(i, n) {
        d[i][i] = 0;
        queue<int> q;
        q.push(i);
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            for(int v : e[u]) {
                if(d[i][v] > d[i][u] + 1) {
                    d[i][v] = d[i][u] + 1;
                    q.push(v);
                }
            }
        }
    }
    vector<array<int, 3>> f(n);
    FOR(i, 1, n - 1) {
        FOR(j, 1, n - 1) {
            if(i == j) continue;
            if(d[0][j] > k + 1 || d[j][i] > k + 1) continue;
            if(a[j] >= a[f[i][0]]) {
                f[i][2] = f[i][1];
                f[i][1] = f[i][0];
                f[i][0] = j;
            }
            else if(a[j] >= a[f[i][1]]) {
                f[i][2] = f[i][1];
                f[i][1] = j;
            }
            else if(a[j] >= a[f[i][2]]) {
                f[i][2] = j;
            }
        }
    }
    ll ans = 0;
    FOR(i, 1, n - 1) {
        FOR(j, 1, n - 1) {
            if(i == j) continue;
            if(d[i][j] > k + 1) continue;
            REP(l, 3) {
                REP(r, 3) {
                    if(!f[i][l] || !f[j][r]) continue;
                    if(f[i][l] != f[j][r] && f[i][l] != j && f[j][r] != i) {
                        chmax(ans, a[i] + a[j] + a[f[i][l]] + a[f[j][r]]);
                    }
                }
            }
        }
    }
    cout << ans << endl;
}

B 策略游戏

简单的博弈论。
首先像第二个人的策略,因为第一个人会思考第二个人的策略。
假如第一个人选了正数,那么第二个人就需要选最小值,反之亦然。
然后讨论第一个人的策略。
如果第二个数组都是正数,那肯定选最大值,反之亦然。
如果有正有负,那第二个人就肯定要把最终答案变成负数,
所以要尝试正数的最小值和负数的最大值。
用六个 \(\mathrm{ST}\) 表维护。

void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    vector<int> a(n + 1), b(m + 1);
    FOR(i, 1, n) cin >> a[i];
    FOR(i, 1, m) cin >> b[i];
    sparse_table_max<int> A1(n, a);
    sparse_table_min<int> A2(n, a);
    sparse_table_max<int> B1(m, b);
    sparse_table_min<int> B2(m, b);
    vector<int> s(n + 1);
    FOR(i, 1, n) s[i] = (a[i] >= 0 ? -INF : a[i]);
    sparse_table_max<int> A3(n, s);
    FOR(i, 1, n) s[i] = (a[i] < 0 ? INF : a[i]);
    sparse_table_min<int> A4(n, s);
    REP(i, q) {
        int l1, r1, l2, r2;
        cin >> l1 >> r1 >> l2 >> r2;
        int a1 = A1.query(l1, r1);
        int a2 = A2.query(l1, r1);
        int a3 = A3.query(l1, r1);
        int a4 = A4.query(l1, r1);
        int b1 = B1.query(l2, r2);
        int b2 = B2.query(l2, r2);
        ll ans = -LINF;
        chmax(ans, 1ll * a1 * (a1 >= 0 ? b2 : b1));
        chmax(ans, 1ll * a2 * (a2 >= 0 ? b2 : b1));
        if(a3 != -INF) chmax(ans, 1ll * a3 * (a3 >= 0 ? b2 : b1));
        if(a4 != INF) chmax(ans, 1ll * a4 * (a4 >= 0 ? b2 : b1));
        cout << ans << endl;
    }
}

C 星战

首先转换题意,题目有加边和删边操作,询问当前每个点的出度是否都为 \(1\)
那就是每个点的入度总集合等于所有的点,
用合哈希维护即可。

void solve() {
    mt19937 rd(time(0));    
    int n, m;
    cin >> n >> m;
    ll ans = 0, res = 0;
    vector<int> a(n + 1);
    FOR(i, 1, n) {
        a[i] = rd();
        ans += a[i];
    }
    vector<ll> f(n + 1), g(n + 1);
    REP(i, m) {
        int u, v;
        cin >> u >> v;
        f[v] += a[u];
        res += a[u];
        g[v] = f[v];
    }
    int q;
    cin >> q;
    REP(i, q) {
        int opt, u, v;
        cin >> opt;
        if(opt == 1) {
            cin >> u >> v;
            f[v] -= a[u];
            res -= a[u];
        }
        if(opt == 2) {
            cin >> u;
            res -= f[u];
            f[u] = 0;
        }
        if(opt == 3) {
            cin >> u >> v;
            f[v] += a[u];
            res += a[u];
        }
        if(opt == 4) {
            cin >> u;
            res += g[u] - f[u];
            f[u] = g[u];
        }
        cout << (ans == res ? "YES" : "NO") << endl;
    }
}
posted @ 2023-07-19 14:06  KevinLikesCoding  阅读(28)  评论(0编辑  收藏  举报