Codeforces911 D. Inversion Counting(逆序数)

题目链接:http://codeforces.com/problemset/problem/911/D

D. Inversion Counting

A permutation of size n is an array of size n such that each integer from 1 to n occurs exactly once in this array. An inversion in a permutation p is a pair of indices (i, j) such that i > j and ai < aj. For example, a permutation [4, 1, 3, 2] contains 4 inversions: (2, 1), (3, 1), (4, 1), (4, 3).

You are given a permutation a of size n and m queries to it. Each query is represented by two indices l and r denoting that you have to reverse the segment [l, r] of the permutation. For example, if a = [1, 2, 3, 4] and a query l = 2, r = 4 is applied, then the resulting permutation is [1, 4, 3, 2].

After each query you have to determine whether the number of inversions is odd or even.

Input

The first line contains one integer n (1 ≤ n ≤ 1500) — the size of the permutation.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ n) — the elements of the permutation. These integers are pairwise distinct.

The third line contains one integer m (1 ≤ m ≤ 2·105) — the number of queries to process.

Then m lines follow, i-th line containing two integers liri (1 ≤ li ≤ ri ≤ n) denoting that i-th query is to reverse a segment [li, ri] of the permutation. All queries are performed one after another.

Output

Print m lines. i-th of them must be equal to odd if the number of inversions in the permutation after i-th query is odd, and even otherwise.

Description:

给出一个长度为n的排列,m次操作,每次操作给出区间 [l,r],使原排列中 a[l] ~ a[r] 的元素反转,求每次反转之后新排列的逆序数

 

Solution:

先求出所有的逆序数ans,对于一次操作 [L,R] 之间这 t =(R-L+1)个数,在反转区间之后,任意两个数之间都相当于交换了位置,由于任意两个数都不相等,所以每有一次交换,ans的奇偶就改变一次(共有组合数 C(t, 2) 个交换)。

对于 a ^= 1,运算一次a的奇偶性就变一次

 

Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
const int MaxN = 1e5 + 5;

int a[1505];

int main() {
	int n, m;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int ans = 0;
	for(int i = 1; i <= n; i++) 
		for(int j = i + 1; j <= n; j++)
			if(a[i] > a[j]) ans ^= 1;  //先求出所有逆序数,判断奇偶
	scanf("%d", &m);
	while(m--) {
		int l, r;
		scanf("%d %d", &l, &r);
		int t = r - l + 1;
		t = t * (t - 1) / 2; //翻转序列相当于序列中任意两个数都交换了位置
		if(t & 1) ans ^= 1;
		if(ans) printf("odd\n");
		else printf("even\n");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值