前缀和和位运算的基本运用。另外还有贪心的思想。

关于位运算上的数什么时候取1,这取决于当前区间上的数中该位置是1多还是0多。

因为多组解要求最小的,所以只有当1的个数严格<总个数的一半的时候,X的这一位才取1。

没有必要给中间值开double,直接让前面乘以2即可。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int cnt[100007][40];
void turn(int n,int x)
{
    int m = 0;
    for (int i = 0; i <= 30; i++)cnt[n][i] += cnt[n - 1][i];//前缀和处理
    while (x)
    {
        if (x & 1)cnt[n][m]++;
        x >>= 1;
        m++;
    }
}
long long quick(int x,int n)//快速幂
{
    long long tmp = x, ans = 1;
    while (n)
    {
        if (n & 1)ans = ans * tmp;
        n >>= 1;
        tmp *= tmp;
    }
    return ans;
}
long long deal(int l,int r)
{
    long long ans = 0;
    int n = r - l + 1;//区间长度。注意这里的n不是总长度。本人被卡这里
    for (int i=0;i<=30;i++)
    {
        if ((cnt[r][i] - cnt[l - 1][i])*2<n)//数量比较
        {
            ans += quick(2,i);
        }
    }
    return ans;
}
int main()
{
    int n;
    cin >> n;
    for (int i=1;i<=n;i++)
    {
        int x; scanf("%d",&x);
        turn(i,x);
    }
    int q; cin >> q;
    int l, r;
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d",&l,&r);
        printf("%lld\n",deal(l,r));
    }
    return 0;
}