#4706. 异或

题目描述

题解

考虑答案转化为两个前缀和相减,也就是求 $\sum_{i=0}^{n}f^2(i \wedge x)$

考虑最高位,如果 $n$ 在第 $k$ 位是 $0$ 的话,那就变成 $[0,n] \wedge x'$ 或 $[2^k,n+2^k] \wedge x'$ , $x'$ 是去掉第 $k$ 位的值

如果 $n$ 在第 $k$ 位是 $1$ 的话,那有 $[0,2^k)$ 和 $[2^k,n]$ 两个范围,其中前面区间和 $x'$ 异或肯定还是这个区间内的取值,另一边递归往下做就好了

所以我们现在有 $[0,n]$ ,如何求 $\sum_{i=0}^nf^2(i)$

考虑把 $a_i$ 排序,然后在每个 $a_i$ 预处理出一个答案,然后我们只要二分到最后一个小于等于 $n$ 的 $a_i$ 即可

效率: $O(30qlogn)$

代码

#include 
#define _(d) while(d(isdigit(c=getchar())))
using namespace std;
int R(){char c;_(!);int x=(c^48);_()x=(x<<3)+(x<<1)+(c^48);return x;}
int ww[20];
void W(int x){
    if (!x){putchar(48);return;}
    int v=0;while(x) ww[++v]=x%10,x/=10;
    for (int i=v;i;i--) putchar(ww[i]^48);
}
const int N=1e5+5,P=998244353;
int n,q,a[N],b[N],B,s[N];
int X(int x){return x>=P?x-P:x;}
int qry(int x){
    int v=upper_bound(b+1,b+B+1,x)-b-1;
    if (!v) return 0;
    int u=upper_bound(a+1,a+n+1,x)-a-1;
    return X(s[v-1]+1ll*u*u%P*(x-b[v]+1)%P);
}
int qry(int m,int x){
    if (m<0) return 0;int v=0,w=0;
    for (int u,y,i=29;~i;i--){
        y=(1<y);
        if ((m>>i)&1){
            v=X(v+X(qry((w|u)+y-1)-qry((w|u)-1)+P));
            w|=(y^u);
        }
        else w|=u;
    }
    return X(v+X(qry(w)-qry(w-1)+P));
}
int main(){
    n=R();q=R();
    for (int i=1;i<=n;i++)
        b[++B]=a[i]=R();
    sort(a+1,a+n+1);sort(b+1,b+n+1);
    B=unique(b+1,b+B+1)-b-1;
    for (int v,i=1;i){
        v=upper_bound(a+1,a+n+1,b[i])-a-1;
        s[i]=X(s[i-1]+1ll*(b[i+1]-b[i])*v%P*v%P);
    }
    for (int l,r,x;q--;)
        l=R(),r=R(),x=R(),
        W(X(qry(r,x)-qry(l-1,x)+P)),putchar('\n');
    return 0;
}

 

你可能感兴趣的:(#4706. 异或)