Codeforces Round #485 (Div. 2)E. Petr and Permutations

这里写图片描述
题意:
给定n,代表原排列为(1,2,3….n)
再给一个排列,问该排列是通过随机3n次交换(两个元素交换位置)还是7n+1次交换得到的。
思路:
1.全排列知识,排列发生一次元素交换,排列的奇偶性改变。
2.求给出排列的逆序数,可以得到该排列 奇偶性,逆序数为奇数即为奇排列,否则为偶排列。
3.因为3n、7n+1本身的奇偶性就不同,因此判断逆序数与3n、7n+1的奇偶性就可以得到答案。
逆序数为奇数,说明给出的排列是由奇数次交换得到的
否则为偶数次交换得到的
求逆序数可以用归并排序或树状数组。。。

代码:(归并排序)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll; 
    int const maxn=1000005;


    int a[maxn];
    int b[maxn];
    int n; 
    ll Reverse=0;

    int parites(int x){ 
        if(x&1)return 1;
        else return 0;
    } 

    void Merge(int l,int r,int ll,int rr){


        int i=l;
        int j=ll;
        int id=l;
        while(i<=r&j<=rr){
            if(a[i]<=a[j]){
                b[id]=a[i];
                id++;i++;
                continue;
            }
            else{
                Reverse+=(r-i+1);
                b[id]=a[j];
                j++,id++;
                continue;
            }
        }
        while(i<=r){
            b[id]=a[i];
            i++;
            id++;
        }
        while(j<=rr){
            b[id]=a[j];
            j++;
            id++;
        }
        for(int i=l;i<=rr;i++){
            a[i]=b[i];
        }

    }
    void merge_sort(int l,int r){
        if(l<r){
            int mid=(l+r)>>1;
            merge_sort(l,mid);
            merge_sort(mid+1,r);
            Merge(l,mid,mid+1,r);
    }
    else return ;

    }



    void By_Merge_sort(){
        merge_sort(1,n);
        //cout<<Reverse<<endl;

        if(parites(Reverse)==parites(3*n))
        cout<<"Petr";
        else
        cout<<"Um_nik";

    }
    int main(){

        scanf("%d",&n);

        for(int i=1;i<=n;i++)scanf("%d",&a[i]);

        By_Merge_sort();

        return 0;
    }
    #include<bits/stdc++.h>
    using namespace std;
    int const maxn=1000005;
    typedef long long ll; 
    int c[maxn*4];
    int a[maxn];
    int b[maxn];
    int n; 
    ll Reverse=0;


    int parites(int x){
        if(x&1)return 1;
        else return 0;
    } 

    int lowbit(int x){
        return (x&(-x));
    }
    void Add(int x,int v){
        for(int i=x;i<=n;i+=lowbit(i)){
            c[i]+=v;
        }
    }

    ll Sum(int x){
        ll ans=0;
        for(int i=x;i>=1;i-=lowbit(i)){
            ans+=c[i];
        }
        return ans;
    }

    ll ask(int l,int r){
        return Sum(r)-Sum(l-1);
    }

    void By_Binary_Tree(){

        ll ans=0;
        for(int i=1;i<=n;i++){
            Add(a[i],1);
            int sm=Sum(a[i]);
            ans+=(i-sm);
            //cout<<ans<<endl;
        }

        if(parites(3*n)==parites(ans)){
            cout<<"Petr";
        }
        else
        cout<<"Um_nik";
    }


    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }

        By_Binary_Tree();




        return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值