首页 > 其他分享 >ABC381 C-E题解

ABC381 C-E题解

时间:2024-12-11 13:20:26浏览次数:4  
标签:std cnt int 题解 pos st ABC381 ans

C - 11/22 Substring

枚举每个 /,从 / 出发向左右两边扩展到最远。因为每个点最多能被访问一次(向右只扩展 2,向左只扩展 1),复杂度为 \(O(n)\)。

int ans = 0;
for (int i = 0; i < n; i++) {
    if (s[i] != '/') continue;
    int l = i - 1, r = i + 1, len = 1;
    while (l >= 0 && r < n && s[l] == '1' && s[r] == '2')
        len += 2, l--, r++;
    ans = max(ans, len);
}
cout << ans << '\n';

D - 1122 Substring

考虑从头开始遍历,如果当前 \(a_i\neq a_{i+1}\) 则跳过(每次往后走一步),\(a_i=a_{i+1}\) 则开始记录(每次往后走两步),直到 不相等 或者 出现了重复的数字。如果是前者,统计答案,清空长度即可。对于后者,需要开一个 unordered_map 记录当前 1122 数列里每个数字出现的位置。一旦重复,就更新答案,然后把当前 1122 数列的开头 \(st\) 到重复数字第一次出现的位置 \(ed\) 中间的数字全部扔掉,\(st\gets ed+2\) 继续向后找。因为每个数字最多被扔掉一次,所以复杂度仍为 \(O(n)\)。

但是发现这个算法没法处理 11122 这种情况,它注意不到 1122 的部分,而是在 1112 失配之后直接跳到 22 了。想到我们可以按开头位置的奇偶性分开处理。强制开头为奇数跑一遍,强制开头为偶数跑一遍,最后答案取最大值即可。

int ans = 0;
auto startFrom = [&](int x) {
    int st = -1;
    map<int, int> mp;
    for (int i = x; i < n; i += 2) {
        if (i == n - 1 || a[i] != a[i + 1]) { // 如果i=n-1则肯定失配
            if (st != -1) {
                ans = max(ans, i - st);
                st = -1;
                mp.clear();
            }
            continue;
        }
        if (st == -1) st = i;
        if (mp.count(a[i])) {
            ans = max(ans, i - st);
            int ed = mp[a[i]];
            for (int j = st; j <= ed; j += 2)
                mp.erase(a[j]); // 清除st~ed之间的数
            st = ed + 2;
        }
        mp[a[i]] = i;
    }
    if (st != -1) ans = max(ans, n - st);
};
startFrom(0), startFrom(1);
cout << ans << '\n';

E - 11/22 Subsequence

朴素的想法是枚举每个区间中的 /,用前缀和计算它前面的 1 的个数 \(cnt_1\) 和后面的 2 的个数 \(cnt_2\),用 \(\min(cnt_1,cnt_2)\) 更新答案,但枚举 / 是 \(O(n)\) 的,复杂度过高。

注意到从前到后枚举区间内 / 的过程中,\(cnt_1\) 单调增加,\(cnt_2\) 单调减少,\(\min(cnt_1,cnt_2)\) 的最大值一定取在 \(cnt1<cnt_2\) 到 \(cnt_1>cnt_2\) 的交界处(之前 \(cnt_1\) 是最小值,不断增大;之后 \(cnt_2\) 是最小值,不断减小)。这个过程是有单调性的,可以二分,复杂度为 \(O(q\log n)\)。

int n, q;
std::string s;
std::cin >> n >> q >> s;
std::array<std::vector<int>, 2> cnt{std::vector<int>(n), std::vector<int>(n)}; // 12前缀和
std::vector<int> pos; // 记录/的位置
for (int i = 0; i < n; i++) {
    s[i] == '/' ? pos.emplace_back(i) : cnt[s[i] - '1'][i]++;
}
std::partial_sum(cnt[0].begin(), cnt[0].end(), cnt[0].begin()); // 自动前缀和
std::partial_sum(cnt[1].begin(), cnt[1].end(), cnt[1].begin());
auto getSum = [&](int i, int l, int r) {
    return cnt[i][r] - (l ? cnt[i][l - 1] : 0);
};
auto calc = [&](int l, int r) -> int {
    int L = std::lower_bound(pos.begin(), pos.end(), l) - pos.begin(); // 区间内第一个/
    int R = std::upper_bound(pos.begin(), pos.end(), r) - pos.begin() - 1; // upper_bound求出大于r的第一个/,-1得到区间内的最后一个/
    if (R < L) return 0; // 区间内没有/
    int i = *std::ranges::partition_point(std::ranges::iota_view(L, R), [&](int x) -> bool {
        return getSum(0, l, pos[x]) <= getSum(1, pos[x], r);
    }); // 二分,找到第一个cnt1>cnt2的位置
    int res = 0; // min(cnt1,cnt2)的最大值
    if (i <= R) res = std::max(res, std::min(getSum(0, l, pos[i]), getSum(1, pos[i], r)));
    if (i >= L + 1) res = std::max(res, std::min(getSum(0, l, pos[i - 1]), getSum(1, pos[i - 1], r))); // 也可能在最后一个cnt1<=cnt2的位置上取得,峰的位置不一定在哪边
    return res * 2 + 1;
};
for (int l, r; q--;) {
    std::cin >> l >> r;
    std::cout << calc(l - 1, r - 1) << '\n';
}

因为有大小相等的点,不能三分。

标签:std,cnt,int,题解,pos,st,ABC381,ans
From: https://www.cnblogs.com/th19/p/18599281

相关文章

  • Luogu P9606 CERC2019 ABB 题解 [ 绿 ] [ KMP ] [ 字符串哈希 ]
    ABB:KMP的做法非常巧妙。哈希思路显然正着做一遍哈希,倒着做一遍哈希,然后枚举回文中心即可。时间复杂度\(O(n)\)。代码#include<bits/stdc++.h>#definefifirst#definesesecond#definelc(p<<1)#definerc((p<<1)|1)usingnamespacestd;typedeflonglongll;......
  • ARC161F Everywhere is Sparser than Whole (Judge) 题解
    题意定义一张图的密度为它的边数与点数的比值。给定一张\(n\)个点、\(m=dn\)条边的无向图,记点集为\(V\)。你需要判断,任取\(V\)的非空真子集\(X\),\(X\)的导出子图的密度是否一定严格小于\(d\)。多测,\(1\leqn,d,\summ\leq50000\)。题解对于一张流网络,记\(s,......
  • 河南工大2024新生周赛(7)----命题人 刘义 题解
    问题A:圆:这是一个数学题,画图可得,4个圆时,分割成14个区域,可以推导出结论:当圆为0个时,区域数为1个,当圆有x个的时候,区域数有x*x-x+2;#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongintn;signedmain(){inta,b;//a为圆的个数,b为区域数cin>>......
  • 埃氏筛/线性筛+质数与约数一本通题解
    埃氏筛:筛选\(1...n\)中所有的质数考虑一个质数\(x\),它的\(2x,3x,4x...n/x*x\)都是合数,打上标记即可\(O(NloglogN)\)for(inti=2;i<=n;i++){if(vis[i])continue;p[++cnt]=i;for(intj=i;j<=n/i;j++){vis[i*j]=1;}}线性筛:考虑一个合数......
  • P1541 [NOIP2010 提高组] 乌龟棋 题解
    动规题。动态规划分为3步:1.定义数组元素含义。2.找到数组元素之间的关系式。3.找出初始值。第一步我们不难发现这道题可以现在dp数组中设一个数组dp[i]表示到了第i个格子所获得的最大分数。再思考题目中给的4种卡牌。我们可以发现,dp[i]可以由dp[i-1]+a[i],dp[i-2]+a[i],dp......
  • P9346 无可奈何花落去 题解
    P9346无可奈何花落去题解这个期望第一眼看上去是困难的。然而发现\(E=Px\),贡献\(x\)是可枚举的,于是转化为了一个求概率的问题。这个概率同样难以计算,然而发现状态的个数是有限的,对于选取\(x\)条边断掉它的总方案数就是\({n-1\choosex}\),那么直接求方案数就可以了。想到......
  • Shopee虾皮新手小白必读:十大常见问题解答
     随着跨境电商的兴起,越来越多的新手卖家选择在Shopee(虾皮)平台上开店。以下是针对Shopee新手小白的十大常见问题及其解答,帮助您快速上手,顺利开启您的电商之旅。问题一:没有完成新手任务有什么影响?答:若没有完成,你将会错过对接专属客户经理的机会及部分活动资源。开新店、报名......
  • 题解:P11377 [GESP202412 七级] 武器购买
    思路这是一个典型的背包问题。我们可以设\(dp_{j}\)为武器总强度为\(j\)的情况下的最小花费。于是,根据背包问题的模型我们就能得出:\[dp_j=\max_{1\lei\len}dp_{j-c_i}+p_i\]最终,答案就为第一个大于等于\(P\)的\(dp_j\)的下标\(j\)。时间复杂度为\(O(Tn......
  • CF1601 题解
    纪念一下场切5题。A给定序列\(a\),一次操作可选\(k\)个数,同时减去它们的按位与。问有多少个\(k\)能把\(a\)全消为\(0\)。\(n\le10^5\)。对于一个位,\(1\)的个数的变化量必为\(k\)的倍数。所以\(k\)要是每一位\(1\)的个数的\(gcd\)的因数。B青蛙跳井,初始......
  • Java 架构师面试题解析(2024 年版)
    在当今竞争激烈的技术领域,成为一名Java架构师需要具备深厚的技术功底和丰富的实践经验。为了帮助大家更好地准备Java架构师面试,本文整理了一些2024年常见的面试题及答案解析。一、基础篇1.谈谈你对面向对象编程三大特性的理解?封装:将数据和操作封装在类中,通过访问修......