LGP10650 [ROIR 2017] 排序幻觉 学习笔记
LGP10650 [ROIR 2017] 排序幻觉 学习笔记
题意简述
给定长度为 \(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实际上反应了一种高位和低位之间的连续性和依赖性。
浙公网安备 33010602011771号