Gym 102001H Lexical Sign Sequence 树状数组+贪心

This blog discusses solving the Gym 102001H problem on Codeforces which involves a sequence of 0, 1, and -1. The task is to change 0s to ±1 while satisfying K conditions based on sum intervals. The post presents a solution using a tree array and a greedy strategy with a time complexity of O(N + K * log N)." 111953997,10535397,Python线性回归模型评估与实战,"['Python模型评估', '线性回归']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gym 102001H —— Lexical Sign Sequence

原题链接:http://codeforces.com/gym/102001/problem/H

题目简述

​ 有一个含有0,1,-1的序列,其中的0代表可以换成 ± 1 ​ \pm1​ ±1,并同时满足K个条件。每一个条件由三个整数组成,分别是 A I , B I , C I ​ A_{I},B_{I},C_{I}​ AI,BI,CI,意思是从下标为 A i ​ A_{i}​ Ai的数到下标为 B i ​ B_{i}​ Bi的数的总和,并且总和大于等于 C i ​ C_{i}​ Ci

​ 如果有解,输出字典序最小的序列,否则的话输出 I m p o s s i b l e ​ Impossible​ Impossible

输入说明

第一行输入两个整数 N , K ( 1 ≤ N ≤ 100000 ; 0 ≤ K ≤ 100000 ) ​ N,K(1\le N \le 100000; 0 \le K \le 100000)​ N,K(1N100000;0K100000),分别表示数列的长度与条件的数量。第二列包含 N ​ N​ N个整数 P i ( − 1 ≤ P i ≤ 1 ) ​ P_{i}(-1 \le P_{i} \le 1)​ Pi(1Pi1),若 P i = 0 ​ P_{i} = 0​ Pi=0代表第 i ​ i​ i个位置可以改变为 ± 1 ​ \pm 1​ ±1,反之则代表不能改变。接下来的是K列每一列包含三个整数 A i , B i , C i ( 1 ≤ A i ≤ B i ≤ N ; − N ≤ C i ≤ N ) ​ A_{i},B_{i},C_{i}(1 \le A_{i} \le B_{i} \le N; -N \le C_{i} \le N)​ Ai,Bi,Ci(1AiBiN;NCiN)

输出说明

​ 如果有满足条件的数列存在,输出整个数列,反之输出 I m p o s s i b l e ​ Impossible​ Impossible

样例输入 1

3 2
0 0 0
1 2 2
2 3 -1

样例输出 1

1 1 -1

样例输入 2

3 2
0 -1 0
1 2 2
2 3 -1

样例输出 2

Impssible

解法

​ 用树状数组的方法来解题。先将整个数列初始化为每个值为-1的情况。然后把所有能改能够更改的位置都记录下来。把 K K K行条件记录下来,并用他们的右界 B i B_{i} Bi作为比较条件从小到大排序,因为我们要用贪心的方法从后往前来把所有能改的-1改成1,知道所有条件都能够满足。计算连续和可以用树状数组或者线段树达到需求。记住每次将-1更改为1后,这个位置不能再被更改了。

​ 该解法的时间复杂度是 O ( N + K ∗ l o g N ) O(N + K*logN) O(N+KlogN)

源代码

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

const int SIZE = 1e5+5;
int BTree[SIZE];
bool flag[SIZE];
int arr[SIZE];
int n, k;
struct Node{
    int l, r, num;
}fuck[SIZE];
bool cmp(const Node& a, const Node& b) {
    return a.r < b.r;
}
int lowbit(int x) {
    return x & -x;
}
int sum(int x) {
    int ret = 0;
    while(x > 0) {
        ret += BTree[x];
        x -= lowbit(x);
    }
    return ret;
}
void add(int x, int d) {
    while(x <= n) {
        BTree[x] += d;
        x += lowbit(x);
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
        cin >> arr[i];
        if(arr[i] != 0) flag[i] = true;
        if(arr[i] == 0) arr[i] = -1;
        add(i, arr[i]);
    }
    bool ok = true;
    for(int i = 0; i < k; i++) {
        cin >> fuck[i].l >> fuck[i].r >> fuck[i].num;
    }
    sort(fuck, fuck+k, cmp);
    int a, b, c;
    for(int i = 0; i < k; i++) {
        a = fuck[i].l, b = fuck[i].r, c = fuck[i].num;
        int he = sum(b)-sum(a-1);
        if(he < c) {
            for(int j = b; j >= a && he < c; j--) {
                if(!flag[j]) {
                    he += 2;
                    add(j, 2);
                    arr[j] = 1;
                    flag[j] = true;
                }
            }
        }
        if(he < c) ok = false;
    }
    if(ok) {
        cout << arr[1];
        for(int i = 2; i <= n; i++) {
            cout << " " << arr[i];
        }
        cout << endl;
    } else {
        cout << "Impossible" << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值