Loading

题解 【CF617E XOR and Favorite Number】

\(\Large\texttt{CF617E}\)

\(\small\texttt{In my Blog}\)

这道题其实和P4462几乎一样,但是我却多调了30min,细节很多。洛谷数据太水了QwQ

\(\large\texttt{Meaning}\)

给定 \(n,m,k\) ,共 \(m\) 个询问,每次询问一个区间,问区间内有多少个子区间的异或和等于 \(k\)

\(\large\texttt{Solution}\)

题目中说是区间,则可以转化为前缀和的形式。

\(S_i=a_1~\texttt{xor}~a_2~\texttt{xor}~...~\texttt{xor}~a_i\)

\(a_l~\texttt{xor}~a_{l+1}~\texttt{xor}~a_{l+2}~...~\texttt{xor}~a_r=S_r~\texttt{xor}~S_{l-1}\)

然后每次询问就可转化为在 \([l-1,r]\) 之间有多少个 \(S_i\)\(S_j\) \((i\le j)\) 使得 \(S_i~\texttt{xor}~S_j=k\)

发现这个可以用莫队离线下来做,因为 \(S_i~\texttt{xor}~S_j=k\)\(S_i~\texttt{xor}~k=S_j\)\(S_i\) 数量改变,答案也就相应改变了。

几个要注意的地方,坑点:

  1. 题目中没保证 \(k\) 不为 \(0\) , 即统计贡献的时候要明确,先改贡献,还是先改个数

  2. 数组的上界定为 \(2e6\) 不是 \(1e6\), 我也不知道为啥。

然后处理好细节后,就能过了。

\(\large\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 2e6; //细节2
inline int read()
{
    register int s = 0;
    register bool neg = 0;
    register char c = getchar();
    for (; c < '0' || c > '9'; c = getchar())
        neg |= (c == '-');
    for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
        ;
    return (neg ? -s : s);
}

int a, b, c, s[N + 10], bel[N + 10], p[N + 10], ans, Ans[N + 10];
struct node
{
    int l, r, id;
    bool operator<(const node &t) const
    {
        return (bel[l] ^ bel[t.l]) ? bel[l] < bel[t.l] : (bel[l] & 1 ? r < t.r : r > t.r);
    }
} ask[N + 10];

inline void add(int n)
{
    ans += p[(n ^ c)]; //细节1
    p[n]++;
}

inline void del(int n)
{
    p[n]--; //细节1
    ans -= p[(n ^ c)];
}

signed main()
{
    a = read();
    b = read();
    c = read();
    int k = (int)(sqrt(a));
    for (int i = 1; i <= a; i++)
        bel[i] = (i - 1) / k + 1;
    for (int i = 1; i <= a; i++)
        s[i] = (read() ^ s[i - 1]);
    for (int i = 1; i <= b; i++)
    {
        ask[i].l = read() - 1;
        ask[i].r = read();
        ask[i].id = i;
    }
    sort(ask + 1, ask + b + 1);
    // p[0]= 1;
    int l = 1, r = 0; //其实这里左端点必须设为1,如果设为0,则要先将0这个位置计数1.
    for (int i = 1; i <= b; i++)
    {
        while (l < ask[i].l)
            del(s[l++]);
        while (l > ask[i].l)
            add(s[--l]);
        while (r < ask[i].r)
            add(s[++r]);
        while (r > ask[i].r)
            del(s[r--]);
        Ans[ask[i].id] = ans;
    }
    for (int i = 1; i <= b; i++)
        printf("%lld\n", Ans[i]);
    return 0;
}
posted @ 2020-08-20 10:46  RedreamMer  阅读(153)  评论(0编辑  收藏  举报