CF 986B Petr and Permutations

CF 986B Petr and Permutations

看到两个随机的swap次数,很容易想到跟奇偶性有关。然后就凉了。赛后思考了一下,这个思路应该没问题,那就需要考虑swap的奇偶性与排列的关系。因为,我们考虑如何把两个不相邻数的swap,转换为相邻的数的swap,便于利用逆序数进行推导。假设swap(a[x],a[y]),可以转化为把a[y]向左移动,一直换到x这个位置,再把现在位于x+1这个位置上的a[x]向右移动一直换到y这个位置。显然这个过程一共做了(y-x) + (y-(x+1)) = 2*(y-x)-1次交换,每次交换逆序数的变化的绝对值为1,那么对于一次交换逆序数的变换一定为奇数。那么显然,一个排列的初始逆序数都为0,如果最终的逆序数为奇数,则一定进行了奇数次交换,否则进行了偶数次交换,那结论就很明显了:只要最终的逆序数与某种方式swap次数奇偶性一致,答案就是这种方式。看别人代码发现不用求逆序数,只要求出一种交换方案的,交换次数再判断奇偶性就行了,复杂度比较优秀,用上面的结论,也很好证明,我这里还是用的逆序数的方法,可以过。

#include <cstdio>
typedef long long ll;
const int N = 1e6 + 100;
using namespace std;
int n,a[N],ans=0;
int B[N];
int ask(int x){
    int ans=0;
    for(int i=x;i;i-=(i&(-i)))ans+=B[i];
    return ans;
}
void add(int x,int v) {
    for(int i=x;i<=n;i+=(i&(-i)))B[i]+=v;
}
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;++i) {
        scanf("%d",&a[i]);
        ans+=(ask(n)-ask(a[i]));
        add(a[i],1);
    }
    if((ans&1)==((3*n)&1))puts("Petr");
    else puts("Um_nik");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/9112520.html