NC20861 兔子的逆序对

题目

题目描述

兔子最近喜欢上了逆序对。一个逆序对 \((i,j)\) 需要满足 \(i < j\)\(a_i > a_j\) 。兔子觉得只是求一个序列的逆序对个数太没有意思了。于是兔子想到了一个更有趣的问题!

兔子可以把区间 \([L,R]\) 反转,例如序列 \(\{1,2,3,4\}\) 反转区间 \([1,3]\) 后是 \(\{3,2,1,4\}\) 。兔子有 \(m\) 次反转操作,现在兔子想知道每次反转后逆序对个数是奇数还是偶数,兔子喜欢偶数,而讨厌奇数。

请注意,每一次反转操作都会对原序列进行改变。例如序列 \(\{1,2,3,4\}\) 第一次操作区间 \([1,2]\) 后变成 \(\{2,1,3,4\}\) 第二次反转区间 \([3,4]\) 后变成 \(\{2,1,4,3\}\)

输入描述

第一行一个整数 \(n\) ,表示序列的大小。
第二行 \(n\) 个整数 \(a_i\) 表示序列的各个元素。
第三行一个整数 \(m\) ,表示操作个数。
接下来 \(m\) 行,每行两个整数 \(l\)\(r\),表示反转的区间。

输出描述

输出共 \(m\) 行每行一个字符串,表示反转后序列逆序对个数的奇偶性,如果是逆序对个数奇数,输出"dislike"(不含引号),如果是偶数,输出"like"。

示例1

输入

4
1 2 3 4
4
1 2
3 4
1 4
2 3

输出

dislike
like
like
dislike

说明

注意:以下的 \((i,j)\) 指的是位置 \(i\) 和位置 \(j\)
\(a=\{2,1,3,4\}\) 的逆序对是 \((1,2)\)\(1\) 个,\(1\) 是奇数,所以是dislike
\(a=\{ 2,1,4,3 \}\) 的逆序对是 \((1,2)\) \((3,4)\)\(2\) 个, \(2\) 是偶数,所以是like
\(a=\{3,4,1,2\}\) 的逆序对是 \((1,3)\) \((1,4)\) \((2,3)\) \((2,4)\)\(4\) 个, \(4\) 是偶数,所以是like
\(a=\{3,1,4,2\}\) 的逆序对是 \((1,2)\) \((1,4)\) \((3,4)\)\(3\) 个, \(3\) 是奇数,所以是dislike

备注

对于 \(20\%\) 的数据
\(1 \leq n \leq 100\)
\(1 \leq m \leq 10\)
对于 \(40\%\) 的数据
\(1 \leq n \leq 2000\)
\(1 \leq m \leq 50\)
对于 \(60\%\) 的数据
\(1 \leq n \leq 2000\)
\(1 \leq m \leq 10^4\)
对于 \(100\%\) 的数据
\(1 \leq n \leq 10^5\)
\(1 \leq m \leq 2 \cdot 10^6\)

对于所有数据 \(l \leq r\)\(a_i\)\(n\) 的一个排列,即 \(a_i\) 互不相同且 \(a_i \leq n\)
由于读入数据较大,建议使用快速读入。

题解

知识点:数学,排序,递归。

假设一段长为 \(n\) 的序列的逆序数是 \(x\) ,则反转以后的逆序数是 \(\frac{n(n-1)}{2} - x\) ,因为所有不成逆序的对会变为逆序,而原本逆序的对会变成不逆序的。随后我们发现,反转一段序列会导致逆序数变化量为 \(\frac{n(n-1)}{2} -2x\) ,即决定变化量奇偶性的是 \(\frac{n(n-1)}{2}\) ,如果为偶,则原奇偶性不变;如果为奇,则原奇偶性变化。

时间复杂度 \(O(n\log n + m)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

int a[100007], b[100007], cnt;

inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c>'9') {
        if (c == '-') f = -1;
        c = getchar();
    }///整数符号
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }///挪位加数
    return x * f;
}

void merge_sort(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    merge_sort(l, mid);
    merge_sort(mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while (i <= mid && j <= r) {
        if (a[i] <= a[j]) b[k++] = a[i++];
        else b[k++] = a[j++], cnt += mid - i + 1;
    }
    while (i <= mid) b[k++] = a[i++];
    while (j <= r) b[k++] = a[j++];
    for (int i = l;i <= r;i++) a[i] = b[i];
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n = read();
    for (int i = 0;i < n;i++) a[i] = read();
    merge_sort(0, n - 1);
    bool flag = cnt & 1;
    int m = read();
    while (m--) {
        int l = read(), r = read();
        long long feat = 1LL * (r - l + 1) * (r - l) / 2;
        if (feat & 1)  flag ^= 1;
        if (flag) cout << "dislike" << '\n';
        else cout << "like" << '\n';
    }
    return 0;
}
posted @ 2022-06-23 00:21  空白菌  阅读(47)  评论(0编辑  收藏  举报