Sicily 14514. Bread Sorting


题目
这里写图片描述


思路
题意是说将一组数排列成另外一组数,排序的方式是每次取出3个连续的的数字,然后abc可以cab,也就整体右移,超出位置的到最左边。
问能否排列成目标数组。
额,实在是不会做。在网上找到了好几个人的题解,稍加重写并比较性能好了。
好像和树状数组有关。
如代码区所示。


代码
第一种方法,用时0.9s:
by Per Austrin

//Sample solution for the Bread Sorting problem in NCPC 2012 by Per Austrin
//Rewrite by Weiping Huang
//0.9s

#include <stdio.h>
#include <algorithm>
using namespace std;

int n;
char text[600005];
int A[100005], B[100005], C[100005];

void Readin(int * num) {

    gets(text);
    int sum = 0, k = 0;
    for (int i = 0; text[i] != '\0'; i++) {
        if (text[i] == ' ') {
            num[k++] = sum;
            sum = 0;
        }
        else {
            sum = 10 * sum + (text[i] & 15);
        }
    }
    num[k] = sum;
    //for (int i = 0; i < n; i++) scanf("%d", num + i);
}

int inversions(int n, int * N) {
    if (n < 2) return 0;
    int m = n / 2;
    int r = inversions(m, N) + inversions(n - m, N + m);
    int x = 0, y = m;
    while (x < m && y < n) {
        if (N[y] < N[x]) {
            r += m - x;
            y++;
        }
        else x++;
    }
    sort(N, N + n);
    return r;
}

int main() {

    while (~scanf("%d\n", &n)) {
        Readin(A);
        Readin(B);
        for (int i = 0; i < n; i++) C[B[i]] = i;
        for (int i = 0; i < n; i++) A[i] = C[A[i]];
        printf("%sossible\n", inversions(n, A) & 1 ? "Imp" : "P");
    }

    return 0;
}

第二种方法,用时0.06s:
By Lukáš Poláček (lukasP)

//Sample solution for the Bread Sorting problem in NCPC 2012 by Lukáš Poláček (lukasP)
//Rewrite by Weiping Huang
//0.06s

#include <stdio.h>
#include <string.h>

int n;
char text[600005];
bool seen[100005];
int A[100005], B[100005];

void ReadinA(int * num) {

    gets(text);
    int sum = 0, k = 0;
    for (int i = 0; text[i] != '\0'; i++) {
        if (text[i] == ' ') {
            num[k++] = sum;
            sum = 0;
        }
        else {
            sum = 10 * sum + (text[i] & 15);
        }
    }
    num[k] = sum;
    //for (int i = 0; i < n; i++) scanf("%d", num + i);
}

void ReadinB(int * num) {

    gets(text);
    int sum = 0, k = 0;
    for (int i = 0; text[i] != '\0'; i++) {
        if (text[i] == ' ') {
            num[A[k++] - 1] = sum;
            sum = 0;
        }
        else {
            sum = 10 * sum + (text[i] & 15);
        }
    }
    num[A[k] - 1] = sum;
    //for (int i = 0; i < n; i++) scanf("%d", num + i);
}

int main() {

    while (~scanf("%d\n", &n)) {
        ReadinA(A);
        ReadinB(B);
        memset(seen, false, sizeof(bool) * n);
        int swaps = n;
        for (int i = 0; i < n; i++) {
            if (!seen[i]) {
                swaps--;
                for (int j = i; !seen[j]; j = B[j] - 1) seen[j] = true;
            }
        }
        printf("%sossible\n", swaps & 1 ? "Imp" : "P");
    }

    return 0;
}

第三种方法,用时0.51s:
By Lukáš Poláček (lukasP)

//Sample solution for the Bread Sorting problem in NCPC 2012 by Lukáš Poláček (lukasP)
//Rewrite by Weiping Huang
//0.51s

#include <stdio.h>
#include <string.h>
#include <math.h>

int n;
char text[600005];
int A[100005], B[100005];

struct Buckets {
    int n, b_size;
    int s[100005];
    bool t[100005];
    void clear(int n) {
        b_size = int(sqrt((double)n) + 1.1);
        for (int i = (n + b_size - 1) / b_size - 1; i >= 0; i--) s[i] = 0;
        for (int i = n - 1; i >= 0; i--) t[i] = false;
    }
    void update(int pos) {
        t[pos] = true;
        s[pos / b_size]++;
    }
    int query(int val) {
        int b_ind = val / b_size;
        int res = 0;
        for (int i = 0; i < b_ind; i++) res += s[i];
        for (int i = b_ind * b_size; i < val; i++) res += t[i];
        return res;
    }
}s, t;

void Readin(int * num) {

    gets(text);
    int sum = 0, k = 0;
    for (int i = 0; text[i] != '\0'; i++) {
        if (text[i] == ' ') {
            num[k++] = sum - 1;
            sum = 0;
        }
        else {
            sum = 10 * sum + (text[i] & 15);
        }
    }
    num[k] = sum - 1;
    //for (int i = 0; i < n; i++) scanf("%d", num + i);
}

int main() {

    while (~scanf("%d\n", &n)) {
        long long ia = 0, ib = 0;
        s.clear(n);
        t.clear(n);
        memset(A, 0, sizeof(int) * n);
        memset(B, 0, sizeof(int) * n);
        Readin(A);
        for (int i = 0; i < n; i++) {
        ia += i - s.query(A[i]);
        s.update(A[i]);
        }
        Readin(B);
        for (int i = 0; i < n; i++) {
        ib += i - t.query(B[i]);
        t.update(B[i]);
        }
        printf("%sossible\n", ((ia & 1) != (ib & 1)) ? "Imp" : "P");
    }

    return 0;
}

第四种方法,用时0.33s:
By Andreas Björklund

//Sample solution for the Bread Sorting problem in NCPC 2012 by Andreas Björklund
//Rewrite by Weiping Huang
//0.33s

#include <stdio.h>
#include <string.h>
#include <math.h>

int n, tpn;
char text[600005];
int A[1 << 17], B[1 << 17];
int sum1, sum2;

int count(int* T, int who)
{
    int ix = who;
    int cnt = 0;
    while (ix <= tpn) {
        int inc = ix & -ix;
        cnt ^= (ix <= who) ? T[ix - 1] : 0;
        T[ix - 1] ^= (ix >= who);
        ix ^= inc;
        ix |= (inc << 1);
    }
    return cnt & 1;
}

void ReadinAndCount() {

    sum1 = sum2 = 0;

    gets(text);
    int sum = 0;
    for (int i = 0; text[i] != '\0';) {
        if (text[i] == ' ') {
            i++;
            while (text[i] == ' ') i++;
            sum1 ^= count(A, sum);
            sum = 0;
        }
        else {
            sum = 10 * sum + (text[i] & 15);
            i++;
        }
    }
    sum1 ^= count(A, sum);
    sum = 0;

    gets(text);
    for (int i = 0; text[i] != '\0';) {
        if (text[i] == ' ') {
            i++;
            while (text[i] == ' ') i++;
            sum2 ^= count(B, sum);
            sum = 0;
        }
        else {
            sum = 10 * sum + (text[i] & 15);
            i++;
        }
    }
    sum2 ^= count(B, sum);
    sum = 0;
}

int main() {

    while (~scanf("%d\n", &n)) {
        tpn = 1;
        while (tpn < n) tpn <<= 1;
        for (int i = 0; i < n; i++) A[i] = B[i] = 0;
        ReadinAndCount();
        printf("%sossible\n", sum1 != sum2 ? "Imp" : "P");
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值