二分+模拟,CF1461D - Divide and Summarize

一、题目

1、题目描述

2、输入输出

2.1输入
2.2输出

3、原题链接

Problem - 1461D - Codeforces


二、解题报告

1、思路分析

我们发现每次分裂操作结果都是固定的

我们从初始序列分裂出两个确定的子序列,两个确定的子序列又分裂出4个确定的子序列

那么也就是说我们最终能够分裂出的子序列的数目是O(n)的

我们预处理出所有的子序列就预处理出了所有可以得到的和(当然这个和要在分裂的过程中维护)

而分裂要求我们得到小于等于mid的部分和大于的部分

所以我们需要对原序列进行排序,模拟的过程通过二分来找到分裂的位置

同时预处理前缀和以便每次分裂前都记录一下当前得到的值

值得注意的是numsl = numsr的时候说明当前子序列是相同的,我们无法继续向下分裂

2、复杂度

时间复杂度: O(NlogN)空间复杂度:O(N)

3、代码详解

复制代码
​
cpp 复制代码
#include <bits/stdc++.h>
using PII = std::pair<int, int>;
using i64 = long long;
std::mt19937 rnd(std::chrono::steady_clock::now().time_since_epoch().count());

const int P = [](int x) {
    auto isprime = [](int x) {
        if (x <= 1) return false;
        for (int i = 2; i <= x / i; i ++ )
            if (x % i == 0) return false;
        return true;
    };
    while (!isprime(x)) x ++;
    return x;
}(rnd() % 900000000 + 100000000);

void solve() {
    /*  直接模拟    */
    int N, Q, s;
    std::cin >> N >> Q;
    std::vector<int> nums(N);
    std::vector<i64> pre(N + 1);
    for (int i = 0; i < N; i ++ ) 
        std::cin >> nums[i];
    std::sort(nums.begin(), nums.end());

    for (int i = 0; i < N; i ++ ) 
        pre[i + 1] += nums[i] + pre[i];
    
    std::vector<std::array<int, 2>> segs { { 0, N - 1 } };  segs.reserve(N);
    std::unordered_set<i64> st;

    while (segs.size()) {
        std::vector<std::array<int, 2>> nxt;
        for (auto& [l, r] : segs) {
            st.insert(pre[r + 1] - pre[l] + P);

            if (nums[l] != nums[r]) {
                int mid = std::upper_bound(nums.begin(), nums.end(), (nums[l] + nums[r]) >> 1) - nums.begin();
                nxt.insert(nxt.end(), { { l, mid - 1 }, { mid, r } });
            }
        }
        segs = std::move(nxt);
    }

    for (int i = 0, s; i < Q; i ++) {
        std::cin >> s;
        if (st.count(1LL * s + P))
            std::cout << "YES\n";
        else
            std::cout << "NO\n";
    }
}


int main () {
    std::ios::sync_with_stdio(false);   std::cin.tie(0);  std::cout.tie(0);
    int _ = 1;
    std::cin >> _;
    while (_ --)
        solve();
    return 0;
}
相关推荐
怕浪猫6 小时前
RAG 面试 6 连问,从原理到优化全部覆盖
python·算法·面试
无线通信科研笔记6 小时前
IEEE TVT 2026 论文精读与完整复现|相位误差如何重塑近场 RIS 的幅相响应
论文阅读·人工智能·python·算法·论文笔记
mmmmath_37 小时前
二叉树の递归遍历
算法
All for pursuit.8 小时前
【位运算-1】338.比特位计数
数据结构·c++·算法·leetcode
小师兄吃牛肉8 小时前
C语言中的nullptr有必要吗
c语言·c++·算法
WL学习笔记9 小时前
日期类(C++)
开发语言·c++·日期类实现
H.莓飛10 小时前
【C++】命名空间、缺省参数、函数重载与引用
linux·开发语言·c++·visual studio
一只小小的芙厨10 小时前
【线性DP】
学习·算法·动态规划
奋发向前wcx10 小时前
CSP-J复赛模拟赛5 王晨旭补题 2026.10.5
算法
汉克老师11 小时前
GESP2026年9月认证C++八级( 第一部分选择题(1~7题)精讲
c++·gesp·小学生·学c++编程