fjwc2019 D3T1 签到题 (贪心)
每次询问接近O(1).......考虑贪心
怎么贪心呢?
对于相邻的两个数,我们要保证异或x后单调不降
我们找到两个数二进制上最高的相异位
当左边的数相异位为0,右边为1时,显然x的该位只能为0,否则异或后不符条件。
当左边的数相异位为1,右边为0时,x的该位就必须为1,也就是必须异或一次改变大小关系。
对于剩下的位......取0就行辣
当某位既要取1又要取0,显然就是不符合条件,就是无解了
每次修改的时候把上一位的数据清掉就得了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; void read(int &x){ char c=getchar();x=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); } int n,m,a[1000005],c[33][2]; void add(int id,int k){ if(id==n||id==0) return; if(a[id]==a[id+1]) return ;//重要剪枝 int i=30; while(((a[id]>>i)&1)==((a[id+1]>>i)&1)) --i;//找到最高相异位 c[i][((a[id]>>i)&1)]+=k; } int calc(){ int re=0; for(int i=0;i<=30;++i){ if(c[i][1]){ if(c[i][0]) return -1; re+=1<<i; } }return re; } int main(){ freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); read(n); int q1,q2; for(int i=1;i<=n;++i) read(a[i]); for(int i=1;i<n;++i) add(i,1); printf("%d\n",calc()); read(m); while(m--){ read(q1);read(q2); add(q1,-1); add(q1-1,-1);//把上一位的信息清除掉 a[q1]=q2; add(q1,1); add(q1-1,1); printf("%d\n",calc()); }return 0; }