P8773 选数异或(异或运算+st表)
P8773 选数异或(异或运算+st表)
题意简介
给定一个序列及 \(x\) ,多次询问 \([L,R]\) 区间内是否存在两个数异或值为 \(x\)
思路
预处理出 \(ans\) 数组,其中 \(a_i\) \(\oplus\) \(a_{ans_i}\) \(=\) \(x\), \(ans_i\) 是 \(a_{ans_i}\) 这个值在 \(i\) 位置左侧最后一次出现的位置,由异或运算的性质知 \(a_{ans_i}\) \(=\) \(a_i\) \(\oplus\) \(x\),遍历序列时对于每一个 \(i\),将 \(a_i \oplus x\) 这个值最后一次出现的位置作为 \(ans_i\) 的值
对于每一次询问的区间,找出 \(ans_{L \sim R}\) 中的最大值,若该值在询问区间内出现则成立,考虑使用st表维护区间最值
Code
#include<iostream>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e5+5;
const int LogN=20;
const int MAXN=(1<<20)+5;
int n,m,x,a[N],Log[N],last[MAXN],dp[N],st[N][LogN];
int main()
{
IOS;
cin>>n>>m>>x;
Log[0]=-1;
for(int i=1;i<=n;i++)
cin>>a[i],dp[i]=last[a[i]^x],last[a[i]]=i,Log[i]=Log[i>>1]+1;
for(int i=1;i<=n;i++)
st[i][0]=dp[i];
for(int j=1;j<=Log[n];j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
while(m--)
{
int L,R,k,ans;
cin>>L>>R,k=Log[R-L+1];
ans=max(st[L][k],st[R-(1<<k)+1][k]);
if(ans>=L)
cout<<"yes"<<'\n';
else
cout<<"no"<<'\n';
}
return 0;
}
完结撒花~
浙公网安备 33010602011771号