题目大意:
给你 n n 个数,和 个操作询问,每个询问给你 l,r l , r 两个数,问你反转 l,r l , r 区间的元素后,整个序列的逆序对的个数是奇数个还是偶数个,奇数个输出 odd o d d ,偶数个则输出 even e v e n ,该逆序对以从小到大为标准次序,反转后不会恢复为原序列,且保证 n n 个数中每个数都不相同。
数据范围
解题思路:
因为要求每次操作后逆序对的对数的奇偶性,如果想暴力做的话,每次对序列进行反转就是 O(n) O ( n ) 的复杂度,还得重新求总逆序对个数,总复杂度就变为了 O(n2⋅m) O ( n 2 ⋅ m ) ,这显然会 TLE T L E 的,所以得换个想法,我们先求出初始序列的总逆序对个数 res r e s ,根据 [l,r] [ l , r ] 区间逆序对的变化转换为总逆序对个数,但是真正的个数我们其实并不太需要,只需要知道奇偶性就行了;我们知道一个长度为len长的序列,它的逆序对最多为 len⋅(len−1)/2 l e n ⋅ ( l e n − 1 ) / 2 (假如该序列为从大到小排序,即总逆序对个数为 ( 1+2+3+⋯+(len−1)=len⋅(len−1)/2 1 + 2 + 3 + ⋯ + ( l e n − 1 ) = l e n ⋅ ( l e n − 1 ) / 2 ) 暂且称为满逆序对,那么现逆序对个数即与满逆序对个数有关,若满逆序对个数为偶数个,那么现逆序对奇偶性与原逆序对相同,即为加减偶数个数,可以用 len⋅(len−1)/2 l e n ⋅ ( l e n − 1 ) / 2 代替,否则当满逆序对个数为奇数个时,那么现逆序对奇偶性与原逆序对相反,即为加减奇数个,也可用 len⋅(len−1)/2 l e n ⋅ ( l e n − 1 ) / 2 代替,所以每次只需要将 res+=len⋅(len−1)/2 r e s + = l e n ⋅ ( l e n − 1 ) / 2 后就可以直接判断奇偶性, O(1) 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;
}