• szoj657 【AHSDFZNOI 7.2 WuHongxun】Odd


    【题目大意】

    给出$n$个数$a_1, a_2, ..., a_n$,求有多少个区间$[l, r]$,满足每个数都出现了奇数次。

    $1 leq n leq 2 * 10^5, 0 leq a_i leq 10^6$

    【题解】

    稳爷爷出的noi模拟题(原题来自某地区ioi选拔赛)

    给每个数赋一个随机权值$H_x$,那么问题转化为:

    有多少个区间,使得区间内的数的异或和=区间内出现过的数的异或和。

    这是可以分块的,记$lst_i$表示数$i$上一次出现的位置,令$x = H_{a_i}$那么每次就是给$[1, lst_x]$异或一个数,并且询问$[1, i]$中为0的数的个数。

    分块+map可以做到$O(nsqrt{nlogn})$。但是会被卡。

    分块+hash就能做到$O(nsqrt{n})$了,把hash表的取模开到1000~3000较优。每次暴力就重构一次。重构的时空复杂度是正确的。

    # include <map>
    # include <vector>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int N = 2e5 + 10, M = 1e6 + 10, NB = 500 + 5;
    const int mod = 1e9+7, BLOCK = 400;
    const int MOD = 2339;
    
    int n, m, B, a[N], bl[N], L[N], R[N];
    vector<int> ps;
    ull H[N];
    int lst[N];
    
    struct hasher {
        int head[MOD + 5], w[MOD + 5], nxt[MOD + 5], tot, id, hid[MOD + 5]; ull to[MOD + 5];
        inline void set() {
            tot = 0; id = 0;
            memset(head, 0, sizeof head);
            memset(hid, 0, sizeof hid); 
        }
        inline void reset() {
            tot = 0; ++id;
        }
        inline void add(int u, ull v, int _w) {
            ++tot; nxt[tot] = head[u]; 
            head[u] = tot; to[tot] = v; w[tot] = _w;
        }
        inline void init(int L, int R) {
            add(0, 0, R-L+1);
        }
        
        inline int bg(int x) {
            if(hid[x] == id) return head[x];
            else {
                hid[x] = id;
                return head[x] = 0;
            }
        }
        
        inline void ins(ull x) {
            int hx = x % MOD; 
            for (int i=bg(hx); i; i=nxt[i]) 
                if(to[i] == x) {
                    ++w[i];
                    return ;
                }
            add(hx, x, 1);
        }
        
        inline int query(ull x) {
            int hx = x % MOD;
            for (int i=bg(hx); i; i=nxt[i]) 
                if(to[i] == x) return w[i];
            return 0;
        }
    }solver[NB];
    
    inline ull irand() {
        ull ret = 0;
        for (int i=1; i<=8; ++i) ret = (ret << 15) + rand();
        return ret;
    }
    
    ull tag[NB], c[N];
    inline void dealxor(int x, ull v) {
        if(!x) return ;
        int p = bl[x];
        for (int i=1; i<p; ++i) tag[i] ^= v;
        solver[p].reset(); 
        for (int i=L[p]; i<=x; ++i) {
            c[i] ^= v;
            solver[p].ins(c[i]);
        }
        for (int i=x+1; i<=R[p]; ++i) solver[p].ins(c[i]); 
    }
    
    inline int query(int x) {
        int p = bl[x], ret = 0;
        for (int i=1; i<p; ++i) ret += solver[i].query(tag[i]);
        for (int i=L[p]; i<=x; ++i) if(c[i] == tag[p]) ++ret;
        return ret;
    }
    
    int main() {
    //    freopen("odd2.in", "r", stdin);
        cin >> n;
        for (int i=1; i<=n; ++i) {
            scanf("%d", a+i);
            ps.push_back(a[i]);
        }
        sort(ps.begin(), ps.end());
        ps.erase(unique(ps.begin(), ps.end()), ps.end());
        m = ps.size();
        for (int i=1; i<=n; ++i) a[i] = lower_bound(ps.begin(), ps.end(), a[i]) - ps.begin() + 1;
        for (int i=1; i<=m; ++i) H[i] = irand();
        for (int i=1; i<=n; ++i) bl[i] = (i-1)/BLOCK + 1;
        B = bl[n];
        for (int i=1; i<=B; ++i) L[i] = (i-1) * BLOCK + 1, R[i] = i * BLOCK;
        R[B] = min(R[B], n);
        for (int i=1; i<=B; ++i) solver[i].set(), solver[i].init(L[i], R[i]);
        ll ans = 0;
        for (int i=1; i<=n; ++i) {
            int pre = lst[a[i]]; lst[a[i]] = i;
    //        cerr << i << ' ' << pre << endl;
            dealxor(pre, H[a[i]]);
            ans += query(i);
        }
        cout << ans;
        return 0;
    }
    /*
    4
    2 2 2 3
    Ans = 7
    */
    View Code
  • 相关阅读:
    c# 遮罩
    判断当前task中的运行的activity是否为当前应用
    Chrome+SwitchySharp+myentunnel+SSH
    vps
    系统制作
    vs2010 mfc
    android ndk
    乐 Phone刷机教程(全过程)
    mysql 保留字 冲突
    mysql 存储过程
  • 原文地址:https://www.cnblogs.com/galaxies/p/szoj657.html
Copyright © 2020-2023  润新知