CF986B Petr and Permutations(逆序对)

题目描述

Petr likes to come up with problems about randomly generated data. This time problem is about random permutation. He decided to generate a random permutation this way: he takes identity permutation of numbers from 11 to nn and then 3n3n times takes a random pair of different elements and swaps them. Alex envies Petr and tries to imitate him in all kind of things. Alex has also come up with a problem about random permutation. He generates a random permutation just like Petr but swaps elements 7n+17n+1 times instead of 3n3n times. Because it is more random, OK?!

You somehow get a test from one of these problems and now you want to know from which one.

输入格式

In the first line of input there is one integer nn ( 103≤n≤106103≤n≤106 ).

In the second line there are nn distinct integers between 11 and nn — the permutation of size nn from the test.

It is guaranteed that all tests except for sample are generated this way: First we choose nn — the size of the permutation. Then we randomly choose a method to generate a permutation — the one of Petr or the one of Alex. Then we generate a permutation using chosen method.

输出格式

If the test is generated via Petr's method print "Petr" (without quotes). If the test is generated via Alex's method print "Um_nik" (without quotes).

题意翻译

Petr要打乱排列。他首先有一个从 11 到 nn 的顺序排列,然后进行 3n3n 次操作,每次选两个数并交换它们。

Alex也要打乱排列。他与Petr唯一的不同是他进行 7n+17n+1 次操作。

给定一个 11 到 nn 的排列。问是由谁打乱的。如果是Petr,输出"Petr",否则输出"Um_nik"(不是Alex)

感谢@AKEE 提供翻译

输入输出样例

输入 #1复制

5
2 4 5 1 3

输出 #1复制

Petr

有引理:交换一个排列的两个数,序列的逆序对的奇偶性必然发生变化。

证明可以大致yy一下:当交换的两个数x,y距离小于等于1的时候易证,当大于1的时候将两个数之间的这些数分为三部分(设较大的数为y):大于y的,小于x的以及大于x且小于y的,分别分析逆序数的变化情况即可(注意夹起来的这部分元素自己的逆序数是不变的)。因为一开始整个排列是有序的,逆序数为0,所以若最终的逆序数为奇数说明交换了奇数次,否则交换了偶数次。因此判断一下3n的奇偶性和逆序数相同还是7n+1的奇偶性和逆序数相同即可。洛谷题解区有On做法更牛逼Orz

#include <bits/stdc++.h>
#define N 1000005
using namespace std;
int n, a[1000005], b[1000005];
void add(int x, int y) {
	for(; x <= N; x += (x & -x)) b[x] += y;
}
int ask(int x) {
	int ans = 0;
	for(; x; x -= x & -x) {
		ans += b[x];
	}
	return ans;
}
int main() {
	cin >> n;
	int cnt = 0;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		cnt += ask(n) - ask(a[i]);//因为是排列 不会有相同的数
		add(a[i], 1);
	}
	//逆序对数一开始是0,交换3n次后应该为偶数,交换7n+1次后应该为奇数
	if((cnt & 1) == ((3 * n) & 1)) puts("Petr");
	else puts("Um_nik");
	return 0;
}
上一篇:Permutations


下一篇:模拟简单 LeetCode1486. 数组异或操作