UVA - 1620 Lazy Susan(逆序数)

本文探讨了一种特殊环形序列问题,即通过翻转四个连续数字是否能将序列变为升序。文章提供了两种求逆序数的方法,并得出结论:仅当序列长度为奇数且逆序数为奇数时,翻转无法实现目标;其它情况皆可行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

把1~n(n≤500)放到一个圆盘里,每个数恰好出现一次。每次可以选4个连续的数字翻转顺序。问能不能变成1.2.3....n的顺序。

思路:

这样的题的规律真的是一点都不好推,看了网上的博客知道只有n为奇数且给出的序列的逆序数为奇数的时候,这种情况下是不能完成的,其余的情况都可以。

如果n为偶数,那么在这个环中总有4个连续的数字的逆序数是偶数,假设4个数的逆序数是x,翻转之后逆序数变成了6-x(为什么是6-x自己还没有搞懂),逆序数的变化为6-2x为偶数。最后升序的逆序数是0为偶数。根据偶数+(-)偶数=偶数,奇数+(-)偶数=奇数,可以得知当序列的逆序数为偶数时,那就可以通过翻转是逆序数变为0.

代码:

树状数组求逆序数

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define MAX 1e3
#define FRE() freopen("in.txt","r",stdin)
#define FRO() freopen("out.txt","w",stdout)
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 600;
int a[maxn],n,tree[maxn];

int lowbit(int x){
    return x&(-x);
}

void add(int x){
    while(x<=n){
        tree[x]++;
        x += lowbit(x);
    }
}

int getSum(int x){
    int res = 0;
    while(x>0){
        res+=tree[x];
        x -= lowbit(x);
    }
    return res;
}

int main(){
    //FRE();
    int kase;
    scanf("%d",&kase);
    while(kase--){
        memset(tree,0,sizeof(tree));
        scanf("%d",&n);
        int cnt = 0;
        for(int i=0; i<n; i++){
            scanf("%d",&a[i]);
            add(a[i]);
            cnt += i+1-getSum(a[i]);
        }
        if(cnt%2==1 && n%2==1){
            printf("impossible\n");
        }else{
            printf("possible\n");
        }
    }
    return 0;
}

暴力求逆序数

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define MAX 1e3
#define FRE() freopen("in.txt","r",stdin)
#define FRO() freopen("out.txt","w",stdout)
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 600;
int a[maxn],n;

int main(){
    int kase;
    scanf("%d",&kase);
    while(kase--){
        scanf("%d",&n);
        for(int i=0; i<n; i++){
            scanf("%d",&a[i]);
        }
        int cnt = 0;
        for(int i=1; i<n; i++){
            for(int j=0; j<i; j++){
                if(a[j]>a[i]){
                    cnt++;
                }
            }
        }
        if(cnt%2==1 && n%2==1){
            printf("impossible\n");
        }else{
            printf("possible\n");
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/sykline/p/10347773.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值