前言:题别看错了,最初我看成是要求异或完后结果的最大值,然后写了代码,最后发现答案怎么都是0+31个1。 一看题,原来是求所有异或结果的最大值,那么只要让所有数每一位的1尽可能多就行了,那么就是求所有事每一个二进制位1的个数,1多x那一位就是0,0多x那一位就是1一样多就无所谓了(因为二进制转化成十进制其实是2的(对应位数-1)次方),所以只要每一位所有数那一位1的个数和尽可能多就行。然后看到要不停的查询(最多1e5),那就利用前缀和和差分。 AC代码&思路:
#include<iostream>
using namespace std;
int a[100005];
int sum[100005][35]={0,0};//全局int变量好像默认初始化为0,这里是为了在算第一个前缀和是把前一个数看成0
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin>>n;
int i;
for (int i=1; i<=n; ++i)
{
cin>>a[i];
for (int j=0; j<=30; ++j)
{
sum[i][32-j]=sum[i-1][32-j];//不要把这句写到底下去了,因为求前缀和无论怎么样都要加前面的
if (((a[i]>>j)&1)==1) {++sum[i][32-j];}
}
}
int q,l,r;
cin>>q;
while(q--)
{
cin>>l>>r;
int res=0;
for(int k=2; k<=32; k++)
{ //即sum[r][k]-sum[l-1][k]<=(r-l+1/*植树原理*/)-(sum[r][k]-sum[l-1][k])
if((sum[r][k]-sum[l-1][k])*2 <= r-l+1){res |= 1<<(32-k);}//防溢出用|=代替+=
}
cout<<res<<'\n';
}
return 0;
}
PS:用32-k是为了把第1-32位正向保存在数组中,符合直觉些 下附不用32-k,逆向保存的代码:
#include<iostream>
using namespace std;
int a[100005];
int sum[100005][35]={0,0};//全局int变量好像默认初始化为0,这里是为了在算第一个前缀和是把前一个数看成0
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin>>n;
int i;
for (int i=1; i<=n; ++i)
{
cin>>a[i];
for (int j=0; j<=30; ++j)
{
sum[i][j]=sum[i-1][j];//不要把这句写到底下去了,因为求前缀和无论怎么样都要加前面的
if (((a[i]>>j)&1)==1) {++sum[i][j];}
}
}
int q,l,r;
cin>>q;
while(q--)
{
cin>>l>>r;
int res=0;
for(int k=0; k<=30; k++)
{ //即sum[r][k]-sum[l-1][k]<=(r-l+1/*植树原理*/)-(sum[r][k]-sum[l-1][k])
if((sum[r][k]-sum[l-1][k])*2 <= r-l+1){res |= 1<<k;}//防溢出用|=代替+=
}
cout<<res<<'\n';
}
return 0;
}