1. 程式人生 > 其它 >CF986B Petr and Permutations(逆序對)

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;
}