1 条题解

  • 0
    @ 2025-8-24 22:25:47

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Transparent
    这个家伙好勤快,什么……都留下了

    搬运于2025-08-24 22:25:47,当前版本为作者最后更新于2023-12-13 17:18:21,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    由于与的性质,固定右端点后,区间与和的每一位都是在一点前全为 00,之后全为 11。根据这个性质,可以推出使得与和不同的左端点至多有 6262 个(每两个反转一位)。于是可以暴力维护这些与和相等的区间,并利用异或前缀和查询异或和等于与和的位置的数量。

    与和相等的区间可以直接用 vector 维护,每次暴力更新并合并值相同的区间。查询某区间中异或前缀和恰为某值可以用 map<int,vector<int>> 记录每个值出现的位置,然后二分。

    注意不要把 vectormap 里复制出来。

    时间复杂度 O(nlognlogV)O(n \log n \log V)

    目前最快的代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    using ll=long long;
    
    constexpr int MAXN=1e5+10;
    
    map<int,vector<int>> mp;
    int n,a[MAXN];
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr); cout.tie(nullptr);
    
        vector<pair<int,int>> val;
        cin>>n; int pre=0; ll ans=0; mp[0].emplace_back(0);
        for(int i=1;i<=n;++i) {
            cin>>a[i]; pre^=a[i]; mp[pre].emplace_back(i);
            for(auto &[r,v]:val) v&=a[i];
            val.emplace_back(i,a[i]);
            vector<pair<int,int>> tmp; int p=0,cur=-1;
            for(auto &[r,v]:val) {
                if(cur!=v) {
                    if(p) tmp.emplace_back(p,cur);
                    cur=v;
                }
                p=r;
            }
            tmp.emplace_back(p,cur); swap(tmp,val);
            int lst=0;
            for(auto [r,v]:val) {
                int req=pre^v;
                if(mp.find(req)==mp.end()) {lst=r; continue;}
                auto &vec=mp[req];
                ans+=upper_bound(vec.begin(),vec.end(),r-1)-lower_bound(vec.begin(),vec.end(),lst);
                lst=r;
            }
        }
        cout<<ans<<endl;
    
        return 0;
    }
    
    • 1

    信息

    ID
    6163
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者