1.9 CW 模拟赛 赛时记录

前言

策略不变, 继续搞

看题

4 神秘, 开骗

T1

思路#

先考虑对于一个确定的 a 怎么做
发现一个数能否被删除与删除的顺序无关, 本质上是因为 j,l 并不因为操作而改变
考虑到一个数能被删除, 仅当其在前后缀中都不为最大值, 也就是说可以 O(n) check
那么我们对于一个确定的 a , 可以 O(n) 求出答案, 先写一份这个验证正确性, 要快

成功了, 考虑优化, 这题肯定是冲正解
这种类型的优化其实很典, 考虑不同前缀 a 计算时的重复

你发现维护一个单调递增栈, 每次弹出时, 统计其对当前序列的贡献即可

实现#

框架#

维护一个单调递增栈, 每次弹出时, 统计其对当前序列的贡献即可

代码写短

代码#

#include <bits/stdc++.h>
#define int long long
const int MAXN = 1e5 + 20;
const int MOD = 998244353;
namespace calc {
    int mul(int a, int b) { return a * b % MOD; }
    int add(int a, int b) { return (a + b > MOD) ? a + b - MOD : a + b; }
    int sub(int a, int b) { return (a - b < 0) ? a - b + MOD : a - b; }
    void addon(int &a, int b) { a = add(a, b); }
    void mulon(int &a, int b) { a = mul(a, b); }
} using namespace calc;
int pow2[MAXN];

int n;
int p[MAXN];
bool flag[MAXN]; // 记录是否为前缀最大值

struct monostack {
    std::stack<int> s;
    /*向单调栈中插入, 返回新增贡献*/
    int push(int x) {
        int res = 0;
        while (!s.empty() && s.top() < x) {
            if (!flag[s.top()]) res++;
            s.pop();
        }
        s.push(x);
        return res;
    }
    void clear() {
        while (!s.empty()) s.pop();
    }
} ms;

signed main()
{
    pow2[0] = 1; for (int i = 1; i <= 100000; i++) pow2[i] = mul(pow2[i - 1], 2);
    int T; scanf("%lld", &T);
    while (T--) {
        ms.clear();
        scanf("%lld", &n);
        for (int i = 1; i <= n; i++) scanf("%lld", &p[i]);
        memset(flag, false, sizeof flag);
        int mx = 0; for (int i = 1; i <= n; i++) if (p[i] > mx) mx = p[i], flag[p[i]] = true;

        int ans = 0, res = 0;
        for (int i = 1; i <= n; i++) {
            res += ms.push(p[i]);
            addon(ans, pow2[res]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

T2

被简单题硬控约 1 h , 我也是无敌了

目前得分: 130 pts

思路#

一眼梦熊的题, 无敌了

题意有点神秘啊, 看不懂
摸下样例

博弈的题是有点困难的
考虑梦梦确定选择一个段时, 熊熊怎么选才能最大化最大子段和
这种情况下我们可以分类讨论

  • 最大子段和跨过了梦梦 : 那么梦梦怎么选并不影响答案, 我们可以 O(n) 求出这种情况下的答案, 需要贪心的放置数
  • 最大子段和在梦梦的两侧 : 梦梦怎么选也不影响答案, 我们可以预处理 O(n2) 求出这种情况下的答案
  • 最大子段和的一端在梦梦里面 : 考虑直接对于两种情况分两类讨论即可, 对于同种情况求最大, 对于不同种情况求最小

实现#

框架#

先预处理, 然后再分开计算答案

代码#

#include <bits/stdc++.h>
#define int long long
const int MAXN = 2025;

int n;
int A[MAXN], B[MAXN], C[MAXN << 1], C1[MAXN << 1];
int maxsum[MAXN][MAXN];

signed main()
{
    int T; scanf("%lld", &T);
    while (T--) {
        scanf("%lld", &n);
        for (int i = 1; i <= n; i++) scanf("%lld", &A[i]);
        for (int i = 1; i <= n; i++) scanf("%lld", &B[i]);
        for (int i = 1; i <= n; i++) C[i * 2] = std::min(A[i], B[i]), C[i * 2 - 1] = std::max(A[i], B[i]);

        for (int l = 1; l <= n * 2; l++) {
            if (l % 2 == 0) std::swap(C[l], C[l - 1]);
            int maxsumr = 0, sumr = 0;
            for (int r = l; r <= n * 2; r++){
                sumr += C[r];
                maxsumr = std::max(maxsumr, sumr);
                maxsum[l][r] = maxsumr;
            }
            for (int r = l; r <= n * 2; r++) maxsum[l][r] = std::max(maxsum[l][r], maxsum[l][r - 1]);
        }

        for (int i = 1; i <= n; i++) C[i * 2] = std::max(A[i], B[i]), C[i * 2 - 1] = std::min(A[i], B[i]);
        for (int i = 1; i <= n; i++) C1[i * 2] = std::min(A[i], B[i]), C1[i * 2 - 1] = std::max(A[i], B[i]);
        int ans = 0x3f3f3f3f;
        for (int i = 1; i <= n; i++) { // 外层枚举梦梦选择的段
            int res = 0;
            int suml = 0, maxsuml = 0;
            for (int l = i * 2 - 2; l >= 1; l--) {
                suml += C[l];
                maxsuml = std::max(maxsuml, suml);
            }
            int sumr = 0, maxsumr = 0;
            for (int r = i * 2 + 1; r <= n * 2; r++) {
                sumr += C1[r];
                maxsumr = std::max(maxsumr, sumr);
            }

            res = std::max(res, maxsuml + maxsumr + A[i] + B[i]);
            res = std::max(res, maxsum[1][i * 2 - 2]);
            res = std::max(res, maxsum[i * 2 + 1][n * 2]);

            int a1 = std::min(A[i], B[i]) + maxsuml;
            int a2 = std::max(A[i], B[i]) + maxsumr;
            int b1 = std::max(A[i], B[i]) + maxsuml;
            int b2 = std::min(A[i], B[i]) + maxsumr;

            int ret = std::min(std::max(a1, a2), std::max(b1, b2));
            res = std::max(res, ret);

            ans = std::min(ans, res);
        }
        printf("%lld\n", ans);
    }

    return 0;
}

T3

T2 搞红温了, 优化不到 O(n2) , 真服了, 先看 T3
不行就把 O(n3) 打了跑路, 好像预处理可以做到 O(n2)

反正这些题都没能力打正解, 不如直接把暴力打全

思路#

对于 20% , O(2nnq) 可以通过
只含 2 操作需要做到每次询问 O(1) , 不太会
对于 O(nq) 的部分分, 完蛋了要本质不同, 趋势

实现#

框架#

考虑暴力模拟拿到 20 pts

代码#

#include <bits/stdc++.h>
#define int long long
const int MAXN = 1e5 + 20;
const int MOD = 998244353;
namespace calc {
    int mul(int a, int b) { return a * b % MOD; }
    int add(int a, int b) { return (a + b > MOD) ? a + b - MOD : a + b; }
    int sub(int a, int b) { return (a - b < 0) ? a - b + MOD : a - b; }
    void addon(int &a, int b) { a = add(a, b); }
    void mulon(int &a, int b) { a = mul(a, b); }
} using namespace calc;

int pow2[MAXN];

int n, q;
std::string S;
std::set<std::string> s;

signed main()
{
    scanf("%lld %lld", &n, &q);
    std::cin >> S; S = ' ' + S;
    while (q--) {
        int op, l, r; scanf("%lld %lld %lld", &op, &l, &r);
        if (op == 1) for (int i = l; i <= r; i++) S[i] = '?';
        else {
            s.clear();
            for (int St = 0; St < (1 << (r - l + 1)); St++) {
                std::string nowS = "";
                for (int i = l; i <= r; i++) {
                    if ((St >> (i - l)) & 1) nowS = nowS + S[i];
                }
                if (nowS[0] != '1') continue;
                bool flag = true;
                for (int i = 0; i < nowS.length(); i++) if (nowS[i] == '?') { flag = false; break; }
                if (flag) s.insert(nowS);
            }
            printf("%lld\n", s.size());
        }
    }

    return 0;
}

T4

这题能拿 20 pts 就算成功

目前得分: 120 pts

思路#

送了 10 pts
考虑 x,y10 的部分分, 打个表即可, 但是手算多半要错, 不想拿这 10 pts

代码#

#include <bits/stdc++.h>

int ans[11][11] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 2, 1, 2, 1, 2, 2, 2},
    {0, 1, 0, 0, 1, 0, 1, 0, 2, 1, 1},
    {0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1},
    {0, 2, 1, 1, 0, 1, 1, 1, 1, 0, }
};

int main()
{
    int T; scanf("%d", &T);
    while (T--) {
        int x, y; scanf("%d %d", &x, &y);
        if (x == 1 && y == 1) printf("0\n");
        else {
            printf("%d\n", ans[x][y]);
        }
    }

    return 0;
}

无论结果如何, 尽力了

posted @   Yorg  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示