Codeforces911D---Inversion Counting

img

题目大意:

给你 n 个数,和 m 个操作询问,每个询问给你 l,r 两个数,问你反转 l,r 区间的元素后,整个序列的逆序对的个数是奇数个还是偶数个,奇数个输出 odd ,偶数个则输出 even ,该逆序对以从小到大为标准次序,反转后不会恢复为原序列,且保证 n 个数中每个数都不相同。

数据范围

1n1500,1m2105,1lirin,1ain;

解题思路:

因为要求每次操作后逆序对的对数的奇偶性,如果想暴力做的话,每次对序列进行反转就是 O(n) 的复杂度,还得重新求总逆序对个数,总复杂度就变为了 O(n2m) ,这显然会 TLE 的,所以得换个想法,我们先求出初始序列的总逆序对个数 res ,根据 [l,r] 区间逆序对的变化转换为总逆序对个数,但是真正的个数我们其实并不太需要,只需要知道奇偶性就行了;我们知道一个长度为len长的序列,它的逆序对最多为 len(len1)/2 (假如该序列为从大到小排序,即总逆序对个数为 (1+2+3++(len1)=len(len1)/2) 暂且称为满逆序对,那么现逆序对个数即与满逆序对个数有关,若满逆序对个数为偶数个,那么现逆序对奇偶性与原逆序对相同,即为加减偶数个数,可以用 len(len1)/2 代替,否则当满逆序对个数为奇数个时,那么现逆序对奇偶性与原逆序对相反,即为加减奇数个,也可用 len(len1)/2 代替,所以每次只需要将 res+=len(len1)/2 后就可以直接判断奇偶性,O(1) 出答案。

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = 1500;
int n, m, cnt;
int a[maxn + 5];
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
    for(int i = 1; i <= n; i++) {
        for(int j = i + 1; j <= n; j++)
            if(a[i] > a[j])cnt++;
    }
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        int l, r;
        scanf("%d%d", &l, &r);
        cnt += (r - l + 1) * (r - l) / 2;
        if(cnt & 1)printf("odd\n");
        else printf("even\n");
    }
    return 0;
}

题目链接:Go to!

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dreams___/article/details/79971878
文章标签: 逆序对
个人分类: ACM - 平常水题
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭