[DTOI 2023] B. 去年 11 月卵梦蕾简易钨丝(暴力+数学+优化)

108 篇文章 0 订阅

[DTOI 2023] B. 去年 11 月卵梦蕾简易钨丝

题目背景

大样例已修复

题目描述

给定序列 { a n } \{a_n\} {an},支持两种形如 opt x 操作:

  1. 1 x:删除一个数 x x x,若序列中没有 x x x,则输出 − 1 -1 1 并跳过本次操作,若有多个 x x x,则仅删除一个

  2. 2 x:向序列中插入一个数 x x x

对于每个未被跳过的操作,试求出 a a a 的一个排列 p p p,最小化 ∑ i = 1 n ∣ p i + 1 − p i ∣ \sum \limits_{i=1}^{n} \lvert p_{i+1}-p_i\rvert i=1npi+1pi 的值,即最小化 ∣ p 2 − p 1 ∣ + ∣ p 3 − p 2 ∣ + ⋯ + ∣ p n + 1 − p n ∣ \lvert p_2-p_1\rvert+\lvert p_3-p_2\rvert+\dots+\lvert p_{n+1}-p_n\rvert p2p1+p3p2++pn+1pn 的值,其中 p n + 1 = p 1 p_{n+1}=p_1 pn+1=p1

保证任意时刻序列内至少有 1 1 1 个数。


p p p a a a 的排列当且仅当对于 ∀ x \forall x x ∑ [ p i = x ] = ∑ [ a i = x ] \sum [p_i=x]=\sum [a_i=x] [pi=x]=[ai=x]

简而言之, p p p a a a 经过某种方式重排后的结果。

例如 { 1 , 1 , 4 , 5 , 1 , 4 } \{1,1,4,5,1,4\} {1,1,4,5,1,4} { 1 , 5 , 4 , 1 , 4 , 1 } \{1,5,4,1,4,1\} {1,5,4,1,4,1} 的一个排列,但是 { 1 , 5 , 4 , 1 , 4 , 7 } \{1,5,4,1,4,7\} {1,5,4,1,4,7} 不是。

输入格式

输入共 q + 2 q + 2 q+2 行。

1 1 1 行两个正整数 n , q n, q n,q

2 2 2 n n n 个非负整数 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,,an,代表初始的序列。

3 ∼ q + 2 3 \sim q + 2 3q+2 行,每行两个数 o p t , x opt, x opt,x , 代表一个询问。

输出格式

输出有多行。

每行输出 1 1 1 个数,代表一个未被忽略的询问的答案,否则输出 -1

样例 #1

样例输入 #1

5 3
1 2 3 4 10
1 4
1 10
2 9

样例输出 #1

18
4
16

提示

【样例 1 解释】

对于第一个询问,删除了序列中的数 4 4 4,则当前序列为$ 1, 2, 3, 10 $, 可以证明 18 18 18 为当前序列的最小答案。

对于第二个询问,删除了序列中的数 10 10 10,则当前序列为$ 1, 2, 3 $, 可以证明 4 4 4 为当前序列的最小答案。

对于第三个询问,向序列中添加了一个数 9 9 9,则当前序列为$ 1, 2, 3, 9 $, 可以证明 16 16 16 为当前序列的最小答案。

【样例 2】

见附加文件中的 abs/abs2.inabs/abs2.out

该样例满足测试点 1 ∼ 4 1\sim 4 14 的限制。

【样例 3】

见附加文件中的 abs/abs3.inabs/abs3.out

该样例满足测试点 7 ∼ 10 7\sim 10 710 的限制。

【数据范围与提示】

w w w 为值域大小,对于所有测试数据,保证 n , q ≤ 1 0 6 n,q\leq 10^6 n,q106 0 ≤ w ≤ 1 0 6 0\leq w\leq 10^6 0w106

每个测试点的具体限制见下表:

测试点编号 n , q ≤ n,q\leq n,q w w w
1 ∼ 4 1\sim 4 14 100 100 100 10 10 10
5 ∼ 6 5\sim 6 56 1 0 3 10^3 103 1 0 3 10^3 103
7 ∼ 10 7\sim 10 710 1 0 6 10^6 106 1 0 6 10^6 106

思路

  • 首先,我们先算:最小化 ∣ p 2 − p 1 ∣ + ∣ p 3 − p 2 ∣ + ⋯ + ∣ p n + 1 − p n ∣ \lvert p_2-p_1\rvert+\lvert p_3-p_2\rvert+\dots+\lvert p_{n+1}-p_n\rvert p2p1+p3p2++pn+1pn 的值。

观察式子 ∣ p 2 − p 1 ∣ + ∣ p 3 − p 2 ∣ + ⋯ + ∣ p n + 1 − p n ∣ \lvert p_2-p_1\rvert+\lvert p_3-p_2\rvert+\dots+\lvert p_{n+1}-p_n\rvert p2p1+p3p2++pn+1pn(下记为 S S S),这里的若干个绝对值符号给了我们一些思路,我们设想一种特殊情况:

若满足 ∀ i ∈ [ 1 , n − 1 ] \forall i \in [1, n - 1] i[1,n1],都有 p i + 1 ≥ p i p_{i + 1} \ge p_{i} pi+1pi,则有:

S = p 2 − p 1 + p 3 − p 2 + ⋯ + p k − p k − 1 + p k + 1 − p k + ⋯ + p n − p n − 1 − p n + 1 + p n S= p_2 - p_1 + p_3 - p_2 + \dots + p_{k} - p_{k - 1} + p_{k + 1} - p_{k} + \dots + p_n - p_{n - 1} - p_{n + 1} + p_n S=p2p1+p3p2++pkpk1+pk+1pk++pnpn1pn+1+pn
= p n − p 1 + p n − p n + 1 = p_n - p_1 + p_n - p_{n + 1} =pnp1+pnpn+1
= 2 ( p n − p 1 ) = 2 (p_n - p_1) =2(pnp1)
那么我们什么时候取等呢?
在这里插入图片描述

  • 剩下的我们就维护最大值的最小值,具体见我代码

AC代码

//xxsbhctjbyct

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1e6+10;

int S[N];
int w[N],b[N],cnt;
int n,q;
int maxv,minv=2e9;

int main(){
    cin>>n>>q;
    
    for(int i=1;i<=n;i++){
        cin>>w[i];
        S[w[i]]++;
        maxv=max(maxv,w[i]);
        minv=min(minv,w[i]);
    }
    
    while(q--){
        int op,x;
        cin>>op>>x;
        cnt=0;
        int a=minv,b=maxv;
        if(op==1){
            if(S[x]==0){
                puts("-1");
                continue;
            }
            
            S[x]--;
            
            //找次大值
            if(x==maxv&&S[x]==0){
                for(int i=x;i>=1;i--){
                    if(S[i]){
                        b=i;
                        break;
                    }
                }
            }
            
            //找次小值
            if(x==minv&&S[x]==0){
                for(int i=x;i<N;i++){
                    if(S[i]){
                        a=i;
                        break;
                    }
                }
            }
            maxv=b,minv=a;
            // cout<<"cnt="<<cnt<<endl;
            
            cout<<(2*(b-a))<<endl;
            
        }else{
            
            S[x]++;
            
            if(x>maxv){
                b=x;
                maxv=x;
            }
            if(x<minv){
                a=x;
                minv=x;
            }
            // cout<<minv<<" "<<maxv<<endl;
            
            // cout<<"cnt="<<cnt<<endl;
            
            cout<<(2*(b-a))<<endl;
        }
    }
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值