1 条题解

  • 0
    @ 2025-8-24 22:54:49

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Chx
    Today is a present

    搬运于2025-08-24 22:54:49,当前版本为作者最后更新于2024-01-04 18:31:31,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意

    给出一个长度为 nn 的序列 dd,求:

    $$\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}{((d_i\oplus d_j)+(d_i \otimes d_j))} $$

    其中定义 \oplus 代表二进制下两数相加所得到的 11 的个数, \otimes 代表二进制下较大的减较小的所得到的 11 的个数。

    我们发现当确定了 di\sum\limits d_i 后,种类数的量级也会被确定下来:当我们的序列形如 0,1,2,3,4,5x0,1,2,3,4,5 \dots x 时,did_i 的种类是最多的,但发现这个 xx 并不会很大,设 s=dis=\sum\limits d_i,那么这个 xx 最多在 s\sqrt {s} 的量级,所以直接统计每种 did_i 的数量暴力计算即可。

    我们用 VV 表示值域上界,那么时间复杂度是 O(slogV)O(s \log V) 的,预处理 popcount\operatorname{popcount} 可以做到 O(s)O(s),题解给出的是 O(slogV)O(s \log V) 的解法。

    CodeCode

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e7+5;
    template<typename T>inline void read(T &x){
        x=0;int f=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x*=f;
    }
    int n,cnt[N],d,a[N],len;
    long long ans;
    inline int calc(int x){
        int res=0;
        while(x) ++res,x-=x&-x;
        return res;
    }
    int main(){
        read(n);
        while(n--){
            read(d);
            if(cnt[d]++==0) a[++len]=d;
        }
        for(int i=1;i<=len;++i)
            for(int j=1;j<=len;++j)
                ans+=1ll*cnt[a[i]]*cnt[a[j]]*(calc(a[i]+a[j])+calc(abs(a[i]-a[j])));
        printf("%lld",ans);
        return 0;
    }
    
    
    • 1

    信息

    ID
    9668
    时间
    1000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者