zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    poj 3280 Cheapest Palindrome(区间DP)
    POJ 2392 Space Elevator(多重背包)
    HDU 1285 定比赛名次(拓扑排序)
    HDU 2680 Choose the best route(最短路)
    hdu 2899 Strange fuction (三分)
    HDU 4540 威威猫系列故事――打地鼠(DP)
    HDU 3485 Count 101(递推)
    POJ 1315 Don't Get Rooked(dfs)
    脱离eclipse,手动写一个servlet
    解析xml,几种方式
  • 原文地址:https://www.cnblogs.com/galaxies/p/szoj657.html
Copyright © 2011-2022 走看看