LGP10650 [ROIR 2017] 排序幻觉 学习笔记

LGP10650 [ROIR 2017] 排序幻觉 学习笔记

Luogu Link

题意简述

给定长度为 \(n\) 的整数数列 \(A\)\(m\) 次单点修改。在第 \(0\)\(m\) 次修改后确定一个最小的 \(b\),满足 \((a_1 \oplus b)\le (a_2 \oplus b)\le \cdots (a_n \oplus b)\)

做法解析

这一长为 \(n\) 的数列实质上是对 \(b\)\(n-1\) 个限制条件。我们考虑 \((a_i \oplus b)\le (a_{i+1} \oplus b)\) 怎么限制 \(b\) 的范围:若 \(a_i=a_{i+1}\) 则没有影响,否则设 \(a_i\)\(a_{i+1}\) 不同的最高位为第 \(k\) 位,\(a_i<a_{i+1}\)\(b\) 在此位必须为 \(1\),反之则必须为 \(0\)。所以我们可以把“\(b\) 的第 \(k\) 位必须填 \(0/1\)”这种限制装进桶里。当我们确定 \(b\) 时就从高位往低贪,如果当前位既必须要选 \(0\) 又必须要选 \(1\) 则无解。否则能选 \(0\) 就选 \(0\)

至于修改,实际上就是对桶的四次单点修,十分简单。

代码实现

#include <bits/stdc++.h>
using namespace std;
namespace obasic{
    template <typename _T>
    void readi(_T &x){
        _T k=1;x=0;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
        x*=k;return;
    }
    template <typename _T>
    void writi(_T x){
        if(x<0)putchar('-'),x=-x;
        if(x>9)writi(x/10);
        putchar(x%10+'0');
    }
};
using namespace obasic;
const int MaxN=1e6+5;
int N,A[MaxN],M,X,Y,buc[31][2];
void update(int x,int y,int v){
    for(int i=30,w,cl,cr;~i;i--){
        cl=(x>>i)&1,cr=(y>>i)&1;
        if(cl!=cr){buc[i][cl]+=v;break;}
    }
}
int solve(){
    int res=0;
    for(int i=30;~i;i--){
        if(buc[i][0]&&buc[i][1])return -1;
        if(buc[i][1])res|=(1<<i);
    }
    return res;
}
int main(){
    readi(N);
    for(int i=1;i<=N;i++)readi(A[i]);
    for(int i=1;i<N;i++)update(A[i],A[i+1],1);
    writi(solve()),puts("");
    readi(M);while(M--){
        readi(X),readi(Y);int tmp=A[X];A[X]=Y;
        if(X>1)update(A[X-1],tmp,-1),update(A[X-1],A[X],1);
        if(X<N)update(tmp,A[X+1],-1),update(A[X],A[X+1],1);
        writi(solve()),puts("");
    }
    return 0;
}

反思总结

为什么这题有贪心又有位运算,却不往01Trie上面想呢?因为这道题位与位之间完全无关,而01Trie实际上反应了一种高位和低位之间的连续性和依赖性。

posted @ 2025-02-16 09:13  矞龙OrinLoong  阅读(6)  评论(0)    收藏  举报