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