利用逆序数求解AtCoder Beginner Contest 296——F题

蒟蒻来讲题,还望大家喜。若哪有问题,大家尽可提!

Hello, 大家好哇!本初中生蒟蒻讲解一下AtCoder Beginner Contest 296这场比赛的F题

===========================================================================================

F - Simultaneous Swap

原题

Problem Statement

You are given two sequences of N N N numbers: A = ( A 1 , A 2 , … , A N ) A=(A_1,A_2,\ldots,A_N) A=(A1,A2,,AN) and B = ( B 1 , B 2 , … , B N ) B=(B_1,B_2,\ldots,B_N) B=(B1,B2,,BN).
Takahashi can repeat the following operation any number of times (possibly zero).

Choose three pairwise distinct integers i i i, j j j, and k k k between 1 1 1 and N N N.
Swap the i i i-th and j j j-th elements of A A A, and swap the i i i-th and k k k-th elements of B B B.

If there is a way for Takahashi to repeat the operation to make A A A and B B B equal, print Yes; otherwise, print No.
Here, A A A and B B B are said to be equal when, for every 1 ≤ i ≤ N 1\leq i\leq N 1iN, the i i i-th element of A A A and that of B B B are equal.

Constraints

3 ≤ N ≤ 2 × 1 0 5 3 \leq N \leq 2\times 10^5 3N2×105
1 ≤ A i , B i ≤ N 1\leq A_i,B_i\leq N 1Ai,BiN
All values in the input are integers.

Input

The input is given from Standard Input in the following format:
N N N
A 1 A_1 A1 A 2 A_2 A2 … \ldots A N A_N AN
B 1 B_1 B1 B 2 B_2 B2 … \ldots B N B_N BN

Output

Print Yes if there is a way for Takahashi to repeat the operation to make A A A and B B B equal, and print No otherwise.

Sample Input 1

3
1 2 1
1 1 2

Sample Output 1

Yes
Performing the operation once with ( i , j , k ) = ( 1 , 2 , 3 ) (i,j,k)=(1,2,3) (i,j,k)=(1,2,3) swaps A 1 A_1 A1 and A 2 A_2 A2, and swaps B 1 B_1 B1 and B 3 B_3 B3,

making both A A A and B B B equal to ( 2 , 1 , 1 ) (2,1,1) (2,1,1). Thus, you should print Yes.

Sample Input 2

3
1 2 2
1 1 2

Sample Output 2

No
There is no way to perform the operation to make A A A and B B B equal, so you should print No.

Sample Input 3

5
1 2 3 2 1
3 2 2 1 1

Sample Output 3

Yes

Sample Input 4

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

Sample Output 4

No


题目大意

给定两个序列,可以执行以下操作无数次

  • 寻找 ( i , j , k ) (i, j, k) (i,j,k),交换 a i a_i ai a j a_j aj b i b_i bi b k b_k bk

最后,问能否使这两个序列相等


思路

本题,分三大情况

情况1:
若两个序列中的数在排序之后,下标相同的两个数,若不同,则定然不行!即:两个序列中的数必须都相同!

例如:

3
1 2 2
1 1 2

序列A中有2个2,一个1;而B中有2个1,一个2。这明显是不同的!所以输出No


了解情况1之后,我们来补充一下基础知识:
逆序对:
在一个序列A中,若 A i > A j ( i < j ) A_i > A_j(i < j) Ai>Aj(i<j),则这是个逆序对
逆序数:
就是一个序列中逆序对的数量

奇排列: 序列的逆序数为奇数
偶排列: 序列的逆序数为偶数

定理1: 序列中所有元素不相等,则交换序列的任意两个数,则若是奇排列,会变为偶排列;若是偶排列,会变成奇排列!
定理2: 任意一个n阶排列可经过一系列对换变成标准排列,并且所作对换次数的奇偶性与这个排列的奇偶性相同


情况2:
A中的元素全部不同,则如果两个序列的逆序数的和为奇数,则一定不行;反之,若为偶数,便可以!
证明:
设a1为序列A的逆序数,b1为序列B的逆序数。
若进行一次交换:
a1奇偶性转变,b1奇偶性也会转变!
故a1+b1的奇偶性仍不变

所以若a1+b1为奇数,则永远都是奇数,故肯定不可能相等!
因为如果是偶数,依据定理2可得序列A,B最终肯定可以变为标准排列,所以A,B一定会相等!


其实很好理解,如果A是奇排列,B是偶排列,那么不管变化多少次,A,B始终不可能变为同样的排列,所以A,B永远无法相等!相反,如果,A,B都是奇排列或偶排列,那么经过无数次变化后,一定都会成为标准排列,所以A,B一定能变得相等。


情况3
若A中有两个及以上的元素相同,那么一定可以成功。因为相同元素之间交换不会改变序列的奇偶性,所以如果A是奇排列,B是偶排列,那么A可以通过交换两个不相同的元素来变为偶排列,B可以交换两个相同元素保持其偶排列。这样两个偶排列又回到了情况2。同理:A是偶排列,B是奇排列也一样。可以得出结论,只要有重复元素,一定是可行的。


求逆序数可以用归并排序来解,归并排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),可以通过此题,而不能用双重循环暴力,此时时间复杂度将退化至 O ( n 2 ) O(n^2) O(n2)


代码

#include 
#include 
#include 
#include 
#define int long long
#define endl '\n'
#define psb(i) push_back(i)
#define ppb() pop_back()
#define psf(i) push_front(i)
#define ppf() pop_front()
#define ps(i) push(i)

using namespace std;

typedef pair<int, int> PII;

const int N = 2e5 + 10;

int n;
int q[N], a[N], b[N], c[N], d[N], tmp[N];
set<int> t;

inline int read()
{
    int w = 1, s = 0;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') w = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
    
    return w * s;
}

inline int merge_sort(int q[], int l, int r)
{
	if (l >= r) return 0;
	
	int mid = l + r >> 1;
	int res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);
	
	int k = 1, i = l, j = mid + 1;
	while (i <= mid && j <= r)
		if (q[i] <= q[j]) tmp[k ++] = q[i ++];
		else
		{
			res += mid - i + 1;
			tmp[k ++] = q[j ++];
		}
		
	while (i <= mid) tmp[k ++] = q[i ++];
	while (j <= r) tmp[k ++] = q[j ++];
	
	for (int i = l, j = 1; i <= r; i ++, j ++) q[i] = tmp[j];
	
	return res;
}

signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    
    cin >> n;
    
    for (int i = 1; i <= n; i ++)
    	cin >> a[i], t.insert(a[i]);
    for (int i = 1; i <= n; i ++)
    	cin >> b[i];
    
    memcpy(c, a, sizeof a);
    memcpy(d, b, sizeof b);
    
    sort(c + 1, c + 1 + n);
    sort(d + 1, d + 1 + n);
    
    for (int i = 1; i <= n; i ++)
    	if (c[i] != d[i])
    	{
    		cout << "No" << endl;
    		return 0;
		}
	
	if (t.size() != n)
	{
		cout << "Yes" << endl;
		return 0;
	}
		
	int a1 = merge_sort(a, 1, n), b1 = merge_sort(b, 1, n);
    
    if ((a1 + b1) & 1)
    	cout << "No" << endl;
    else
    	cout << "Yes" << endl;
    
    return 0;
}

你可能感兴趣的:(算法,c++,开发语言)