zoukankan      html  css  js  c++  java
  • CF986B Petr and Permutations

    题意翻译

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

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

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

    感谢@AKEE 提供翻译

    题目描述

    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 1 1 1 to n n n and then 3n 3n 3n 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+1 7n+1 7n+1 times instead of 3n 3n 3n 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 n n n ( 103≤n≤106 10^{3} le n le 10^{6} 103n106 ).

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

    It is guaranteed that all tests except for sample are generated this way: First we choose n n n — 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).

    输入输出样例

    输入样例#1: 
    5
    2 4 5 1 3
    
    输出样例#1: 
    Petr
    

    说明

    Please note that the sample is not a valid test (because of limitations for n n n ) and is given only to illustrate input/output format. Your program still has to print correct answer to this test to get AC.

    Due to randomness of input hacks in this problem are forbidden.

    Solution:

       本题思路贼有意思。

      开始题意没理解,所以简述下题意:给你一个$1——n$的排列,它是由初始为从$1——n$的序列每次交换任意两位得到的,然后A进行了$3n$次操作,$B$进行了$7n+1$次操作,要你判断这个排列是谁操作出来的。

      不难发现$3n$和$7n+1$奇偶性一定互异(显然),然后有一个很重要的性质,那就是排列中逆序数的奇偶性和操作的奇偶性相同,证明:1、首先每次若交换相邻的两位,则必然使得逆序数$+1$或$-1$; 2、任意交换两位,可以理解为先将后面的一个向前移动$k$位,再将前面要移的一位向后移$k-1$位,注意到共移动了$2k-1$次,所以移动一次逆序对变化数量为奇数,那么奇数次移动逆序对数就是奇数,偶数次移动逆序对数就是偶数了。

      于是我们直接树状数组求下逆序数,然后判断一下就好了。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long 
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int N=1e6+1;
    int t[N+5],a[N],n;
    bool f;
    
    il int gi(){
        int a=0;char x=getchar();
        while(x<'0'||x>'9')x=getchar();
        while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar();
        return a;
    }
    
    il void update(int k){while(k<=n)t[k]++,k+=k&-k;}
    
    il int query(int k){int sum=0;while(k)sum+=t[k],k-=k&-k;return sum;}
    
    int main(){
        n=gi();
        For(i,1,n) a[i]=gi();
        Bor(i,1,n) {
            f^=(query(a[i]-1)&1);
            update(a[i]);
        }
        if(n&1) f?puts("Petr"):puts("Um_nik");
        else f?puts("Um_nik"):puts("Petr");
        return 0;
    }
  • 相关阅读:
    关于asp:ImageButton的一点经验
    web测试工具及测试方法
    关于NETSNS社区网站开源代码中一些bug修正的记录
    生成验证码的一段源代码
    我存放文件的空间
    一个简单但界面美观,功能实用的电子商务网站源码
    VS2008脚本调试的一点经验
    web测试的经验总结
    提供收藏夹和设置主页对话框的js语句
    一个界面很不错的blog网站
  • 原文地址:https://www.cnblogs.com/five20/p/9370381.html
Copyright © 2011-2022 走看看