当前位置: 首页 > news >正文

2024 天梯赛——工业园区建设题解

思路

将点 i i i 视为固定点, 点 j j j 视为灵活点,其中 s i = 1 s_{i} = 1 si=1 s j = 0 s_{j} = 0 sj=0。维护四个队列,其中 q 0 q_{0} q0 q 1 q_{1} q1 分别维护还没有被选用的固定点 和 灵活点, Q 0 Q_{0} Q0 Q 1 Q_{1} Q1 分别维护 正在被使用的固定点 和 灵活点。此外,维护一个 rnum 表示当前位置右边(包含当前位置)正在被使用的固定点和灵活点的总数,维护 dis 表示当前的最优答案.

依次求解位置 i = 0, 1, …, n - 1 情况下的最优解,并动态更新队列和rnum,在此基础上探索四个队列的一些基本性质:
x x x 属于 q 0 ∪ q 1 q_{0} \cup q_{1} q0q1 的点 和 y y y 属于 Q 0 ∪ Q 1 Q_{0} \cup Q_{1} Q0Q1 的点

  1. Q 0 Q_{0} Q0 Q 1 Q_{1} Q1 的交集为空 且并集为当前位置的最优解.
  2. 每次更新完队列后,对于任意的 x x x,均有 x > i x > i x>i. 因为当我们扫描到位置 i i i 时,点 x = i x = i x=i 必定属于最优解,因此点 i i i 必定已被加入 Q 0 Q_{0} Q0 或者 Q 1 Q_{1} Q1.
  3. m i n { x } > m a x { y } min \{x\} > max \{y\} min{x}>max{y}. 因为当 存在 x 0 < y 0 x_{0} < y_{0} x0<y0 时,那么 i < x 0 < y 0 i < x_{0} < y_{0} i<x0<y0,将 x 0 x_{0} x0 替换 y 0 y_{0} y0会更优.

如何维护上述数据?

  1. 当扫描到 i 时,如果点 i - 1 属于上一个位置的最优解,那么 rnum -= 1 且 dis -= (2 * rnum - k).

  2. 选用 q 0 q_{0} q0 q 1 q_{1} q1 中的最左端的点 x_left,判断是否允许用来替换 Q 0 Q_{0} Q0 Q 1 Q_{1} Q1 中的最左端的点 y_left。显然,x_left >= i 且 x_left > y_left。当 x_left - i <= i - y_left时,将 x_left 替换 y_left 并更新 rnum 和 dis. 此外,当 x_left 来自 q 0 q_{0} q0 时,它允许替换 Q 0 Q_{0} Q0 Q 1 Q_{1} Q1中的点. 当 x_left 来自 q 1 q_{1} q1 Q 1 Q_{1} Q1的大小 < m 时,它允许替换 Q 0 Q_{0} Q0 Q 1 Q_{1} Q1 中的点,否则只能替换 Q 1 Q_{1} Q1中的点. 循环执行上述步骤,直到条件不能满足.

显然,每一轮替换后,确保 Q 0 Q_{0} Q0 Q 1 Q_{1} Q1 更新为最优解. 此外,当 y y y 在位置 i 被抛弃后,它不可能再成为 位置 j (j > i)的最优解.

时间复杂度: O ( n ) O(n) O(n)

Code

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

void solve() {

    int n, m, k;
    std::cin>>n>>m>>k;
    std::string s;
    std::cin>>s;

    std::vector<i64>ans(n);
    std::vector<int>vis(n);
    std::array<std::queue<int>, 2> q, Q;

    for(int i = 0;i < n;i++) {
        if(s[i] == '1') {
            q[0].push(i);
        } else {
            q[1].push(i);
        }
    }

    m = std::min(m, (int)q[1].size());
    i64 dis = 0, rnum = k;
    for(int i = 0;i < k;i++) {
        if(!q[0].empty() && (!q[1].empty() && Q[1].size() < m)) {
            if(q[0].front() < q[1].front()) {
                Q[0].push(q[0].front());
                dis += q[0].front();
                vis[q[0].front()] = 1;
                q[0].pop();
            } else {
                Q[1].push(q[1].front());
                dis += q[1].front();
                vis[q[1].front()] = 1;
                q[1].pop();
            }

        } else if(!q[0].empty()) {
            Q[0].push(q[0].front());
            dis += q[0].front();
            vis[q[0].front()] = 1;
            q[0].pop();
        } else {
            assert(Q[1].size() < k);
            Q[1].push(q[1].front());
            dis += q[1].front();
            vis[q[1].front()] = 1;
            q[1].pop();
        }
    }

    ans[0] = dis;
    auto Oper = [&] (int i, int j, int p)->bool {
        
        assert(!q[i].empty());
        assert(!Q[j].empty());
        assert(q[i].front() >= p);
        
        if(q[i].front() - p > p - Q[j].front()) {
            return false;
        }
        
        assert(Q[j].front() <= p);
        vis[Q[j].front()] = 0;
        dis -= (p - Q[j].front());
        Q[j].pop();

        dis += (q[i].front() - p);
        vis[q[i].front()] = 1;
        rnum += 1;
        Q[i].push(q[i].front());
        q[i].pop();
        
        return true;
    };

    auto calc = [&](int op, int i) ->bool{

        bool res = false;
        if(op == 0 || Q[1].size() < m) {
            if(!Q[0].empty() && (!Q[1].empty() && m)) {
                int cs = (Q[0].front() < Q[1].front()?0 : 1);
                res = Oper(op, cs, i);
            } else if(!Q[0].empty()) {
                res = Oper(op, 0, i);
            } else if(!Q[1].empty()){
                res = Oper(op, 1, i);
            }
        } else if(m > 0){
            res = Oper(1, 1, i);
        }

        return res;
    };

    for(int i = 1;i < n;i++) {
        
        if(vis[i - 1] == 1) {
            rnum -= 1;
        }

        //  在当前点集的作用下,dis 的更新方式如下:
        dis -= rnum;
        dis += (k - rnum);

        bool ok = true;
        while((!q[0].empty() || !q[1].empty()) && ok) {
            ok = false;
            int cs = -1;
            if(!q[0].empty() && (!q[1].empty() && m)) {
                cs = (q[0].front() < q[1].front()?0 : 1);
            } else if(!q[0].empty()) {
                cs = 0;
            } else if(!q[1].empty() && m){
                cs = 1;
            }
            if(cs != -1) {
                ok = calc(cs, i);
            }
        }
        
        ok = true;
        while(!q[0].empty() && ok) {
            ok = false;
            if(!Q[0].empty() && !Q[1].empty()) {
                int cs = (Q[0].front() < Q[1].front()?0 : 1);
                ok = Oper(0, cs, i);
            } else if(!Q[0].empty()) {
                ok = Oper(0, 0, i);
            } else if(!Q[1].empty()){
                ok = Oper(0, 1, i);
            }
        }

        ans[i] = dis;
    }

    for(int i = 0;i < n;i++) {
        std::cout<<ans[i];
        if(i + 1 < n) {
            std::cout<<" ";
        }
    }
} 
 
int main(){
    
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    
    int t = 1;
    std::cin>>t;
    
    while(t--) {
        solve();
        if(t) {
            std::cout<<"\n";
        }
    }
	return 0;
}

文章转载自:
http://asymptotic.hnsdj.cn
http://castiron.hnsdj.cn
http://cephalization.hnsdj.cn
http://around.hnsdj.cn
http://cervelat.hnsdj.cn
http://blizzard.hnsdj.cn
http://boxroom.hnsdj.cn
http://airhouse.hnsdj.cn
http://casey.hnsdj.cn
http://buyer.hnsdj.cn
http://anachronous.hnsdj.cn
http://cheapside.hnsdj.cn
http://chico.hnsdj.cn
http://chalcophanite.hnsdj.cn
http://bigger.hnsdj.cn
http://advices.hnsdj.cn
http://ceil.hnsdj.cn
http://blandly.hnsdj.cn
http://arm.hnsdj.cn
http://bedsettee.hnsdj.cn
http://antimatter.hnsdj.cn
http://bode.hnsdj.cn
http://changeful.hnsdj.cn
http://attainment.hnsdj.cn
http://cactus.hnsdj.cn
http://arrondissement.hnsdj.cn
http://afterclap.hnsdj.cn
http://buckeye.hnsdj.cn
http://anaesthesiologist.hnsdj.cn
http://angus.hnsdj.cn
http://www.dtcms.com/a/115459.html

相关文章:

  • CF2075D Equalization
  • 代码随想录算法训练营Day21
  • Py一阶段习题汇总
  • 微型导轨的制造工艺中,热处理的目的是什么?
  • 202521 | 远程调用 | 注册中心
  • Go语言-初学者日记(六) 并发编程
  • Nginx-keepalived-高可用
  • cpp经典数论问题
  • celsius与Fahrenheit
  • C++ STL 详解 ——list 的深度解析与实践指南
  • leetcode120.三角形最小路径
  • 小刚说C语言刷题——第16讲 switch语句
  • C++11详解
  • Spring Boot 与 TDengine 的深度集成实践(三)
  • 利用C++编写操作OpenCV常用操作
  • 编程速递-Delphi is 30 Delphi诞生30周年!
  • MySQL-SQL-DQL语句、DQL基本查询、DQL条件查询、DQL分组查询、聚合函数、DQL排序查询、DQL分页查询
  • 【勒让德公式】欧拉筛-阶乘分解
  • 【硬件开发技巧】如何通过元器件丝印反查型号
  • vector模拟实现(2)
  • 蓝桥杯2024年第十五届省赛真题-拔河
  • 专栏:区块链入门到放弃查看目录
  • el-tabs添加按钮增加点击禁止样式
  • ubuntu 配置固定ip
  • getline(cin, )
  • Qt音频输出:QAudioOutput详解与示例
  • 玄机-apache日志分析
  • PDF预览-搜索并高亮文本
  • 基于OpenXLSX库创建的CAPL中可用的解析xlsx文件的DLL
  • traefik k3s配置