首页 > 其他分享 >【SSLOJ 3347】动态逆序对

【SSLOJ 3347】动态逆序对

时间:2024-11-16 14:19:12浏览次数:1  
标签:cnt SSLOJ int 样例 奇偶性 3347 num 逆序

题目大意

给出一个长度为 \(n\) 的排列 \(a\)。每次交换两个数,求逆序对数对 \(2\) 取模的结果。

输入格式
第一行一个正整数\(n\) 。

第二行 \(n\)个数,表示给出的排列 \(a\)。

第三行一个正整数\(q\) 。

接下来 \(q\)行,每行两个正整数 ,表示交换 \(a_i\)和 \(a_j\)。

输出格式
输出共 \(q\)行,表示每次交换后逆序对数对 \(2\)取模的结果。
样例
【输入1样例】

4
1 2 3 4
2
1 2
1 2

【输出1样例】

1
0

【输入2样例】

8
4 1 5 2 6 8 7 3
10
6 4
7 8
2 2
1 1
7 7
1 7
3 3
2 4
2 6
5 7

【输出2样例】

0
1
1
1
1
0
0
1
0
1

对于\(100\%\)的数据,\(n,q\le100000\)

基本思路

首先我们肯定要求修改前的逆序对数,那就要用到树状数组。基本原理是先从大到小将所有数排好,再逐个按位置顺序装进树状数组里,每装进一个就统计它前面有几个数,因为先于它装进去肯定会比它大。但是我们要注意相同大小的数是不能计算逆序对的,所以对于相同的数还要按位置从大到小排

在此之前我们需要注意到题目只要我们给出奇偶性,那么事出反常必有因,这很可能是个结论题,大的方向就是哪些因素会影响逆序对数的奇偶性。

那么对于询问修改的如何统计呢?首先我们要明白若以交换的两个数之间为区间,那么此区间外的逆序对数是不会改变的,因为相对位置不变。

那么我们来考虑区间里面,首先对于两个交换的数肯定会对改变奇偶性产生 \(1\) 的贡献的,因为只要两个数不同交换就会产生加减 \(1\) 的改变。那么对于区间里面的数呢?比\(a_i\)和\(a_j\)都大或都小肯定产生不了贡献。如果夹在它们两个中间呢?那么我们可以轻易得出贡献是加减 \(2\) ,对奇偶性没影响。最终得出结论:只要交换的两个数不相等那么就改变奇偶性。(但在实践上好像只需要位置不同就可以了)

核心代码

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

#define pos second

typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10;
int n,a[N],q,sum[N];
ll ans;
pii cnt[N];
bool compare(pii nx,pii ny){
	if(nx.num==ny.num) return nx.pos>ny.pos;
	return nx.num>ny.num;
}
int query(int x){
	int ret=0;
	for(;x;x-=(x&(-x)))
		ret+=sum[x];
	return ret;
}
int add(int x){
	int ret=query(x-1);
	for(;x<=n;x+=(x&(-x)))
		sum[x]++;
	return ret;
}
int main(){
	freopen("lyk.in","r",stdin);
	freopen("lyk.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		cnt[i].num=a[i];
		cnt[i].pos=i;
	}
	sort(cnt+1,cnt+1+n,compare);
	for(int i=1;i<=n;i++)
		ans+=add(cnt[i].pos);
	ans=ans&1;
	cin>>q;
	for(register int i=1,u,v;i<=q;i++){
		cin>>u>>v;
		if(a[u]!=a[v]) ans=!ans;
		cout<<ans<<endl;
	}
    return 0;
}

标签:cnt,SSLOJ,int,样例,奇偶性,3347,num,逆序
From: https://www.cnblogs.com/drlai/p/18549330

相关文章

  • 题解:「2017 山东一轮集训 Day7」逆序对
    LibreOJ6077前置知识:生成函数、组合数先考虑平方怎么做。\(f_{i,j}\)表示处理了前\(i\)个值,逆序对有\(j\)个。显然可以转移到\(f_{i+1,j},f_{i+1,j+1},f_{i+1,j+2},...,f_{i+1,j+i}\)。然后发现这个东西是个很简单的递推,而且长得很生成函数,于是可以很自然的写成\[1\t......
  • 编写函数:递归求逆序 (Append Code) ★
    Description将输入的一个字符串s逆序输出。编写函数recursive()完成程序:原型:intrecursive();功能:用递归的方法读取输入,并且逆序输出。函数的调用格式见“AppendCode”。InvalidWord(禁用单词)错误:在解决这个题目时,某些关键词是不允许被使用的。如果提交的程序中包含了下......
  • #逆序数(小数据)#xtu
     逆序数是大学线性代数的知识,易知我们要用左边第一个数依次与它右边的数比较大小,然后在用左边第二个数与它右边的数比较,可知我们需要两个循环才能完成所有的数比较大小,代码如下方案一: #include<stdio.h>intmain(){intarr[2000];intn,i=0;scanf("%d",&n);while(n!=......
  • 3193. 统计逆序对的数目
    3193.统计逆序对的数目题目链接:3193.统计逆序对的数目代码如下:classSolution{public: intnumberOfPermutations(intn,vector<vector<int>>&requirements) { vector<int>req(n,-1); req[0]=0; for(auto&p:requirements) { req[p[0]]=......
  • 逆序乘积式
    【问题描述】若两个正整数的乘积,等于两正整数各自逆序后的乘积,则称其为逆序乘积式。编写程序读入两个正整数,然后判断这两个正整数能否构成逆序乘积式。假设两个正整数的乘积不会超过int数据类型的表示范围。【输入形式】从控制台输入以一个空格分隔的两个正整数。【输出形......
  • C++ 逆序乘积式
     题目描述【问题描述】若两个正整数的乘积,等于两正整数各自逆序后的乘积,则称其为逆序乘积式。编写程序读入两个正整数,然后判断这两个正整数能否构成逆序乘积式。假设两个正整数的乘积不会超过int数据类型的表示范围。【输入形式】从控制台输入以一个空格分隔的两个正整数......
  • xtu oj 逆序数(小数据) //冒泡排序
    题目描述给你一个序列x1,x2,…,xn,如果数对<xi,xj>,其中i<j,而xi>xj我们称之为逆序数对。一个序列的逆序数对的数目,称为这个序列的逆序数。比如说序列312,逆序数对为<3,1>和<3,2>,所以这个序列的逆序数为2。现在给你一个数字序列,请求其逆序数。输入每个样例为两行......
  • 《练习题011:阶乘-递归-反向输出-排序-逆序(共9种)》
    《目录》01:阶乘求和02:递归求阶乘03:递归输出04:反向输出05:反向输出II06:设置输出颜色07:算素数08:排序09:逆序列表01:阶乘求和题目求1+2!+3!+…+20!的和。程序分析1+2!+3!+…+20!=1+2(1+3(1+4(…20(1))))res=1foriinrange(20,1,-1):res=i*res+1......
  • 逆序对的数量
    #include<iostream>usingnamespacestd;intnum[100010],temp[100010];longlongcount(intl,intr){if(l>=r)return0;longlongsum=0;intmid=(l+r)>>1;sum+=count(l,mid);sum+=count(mid+......
  • [算法日常] 逆序对
    [算法日常]逆序对定义在一个长度为\(n\)的数组\(a\)中,若存在\(\forall1\lei,j\len\),使得\(a_i>a_j\),则称\(<a_i,a_j>\)为一对逆序对。举个例子,一个长度为\(5\)的数组为:15364则存在\(3\)个逆序对,分别是\(<5,3>,<5,4>,<6,4>\)。解法F1:显然,可以枚举......