432 C. Prime Swaps

题意:给定一个n的排列(n<=100000).定义操作(i,j)为交换a[i]和a[j],i<j,j-i+1为素数.请用不多于5*n次操作将原序列变换为升序.
解法:每次把i和在i位置上的数尝试交换.由哥德巴赫猜想,一个数最多被分为3个质数之和.按照这个进行构造.
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <iostream>
#include <iomanip>
#include <list>
#include <queue>
using namespace std;

typedef long long ll;

const int N = 100005;
int prime[N] = {0},num_prime = 0;
int isNotPrime[N] = {1, 1};
void produce_prime()
{
    for(int i = 2 ; i < N ; i ++)
    {
        if(! isNotPrime[i])
            prime[num_prime ++]=i;
        for(int j = 0 ; j < num_prime && i * prime[j] <  N ; j ++)
        {
            
            isNotPrime[i * prime[j]] = 1;
            if( !(i % prime[j] ) )
                break;
        }
    }
}

vector<int> get_even(int v)
{
    vector<int> ret;
    if (!isNotPrime[v]) {
        ret.push_back(v);
        return ret;
    }
    for (int i = 2; ; ++ i) {
        if (!isNotPrime[i] && !isNotPrime[v - i]) {
            ret.push_back(i);
            ret.push_back(v - i);
            break;
        }
    }
    return ret;
}

vector<int> get_odd(int v)
{
    vector<int> ret;
    if (!isNotPrime[v]) {
        ret.push_back(v);
        return ret;
    }
    ret.push_back(3);
    vector<int> another = get_even(v - 3);
    int size = (int)another.size();
    for (int i = 0; i < size; ++ i) {
        ret.push_back(another[i]);
    }
    return ret;
}

vector<int> get(int v, int op)
{
    if (v % 2 == 1) {
        return get_odd(v);
    }
    vector<int> ret;
    if (!op) {
        return get_even(v);
    }
    ret = get_even(v - 2);
    ret.push_back(2);
    return ret;
}

int a[N], b[N];
vector<pair<int, int> > ans;

void change(int x, int y)
{
    swap(b[a[x]], b[a[y]]);
    swap(a[x], a[y]);
}

int MAIN()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++ i) {
        cin >> a[i];
        b[a[i]] = i;
    }
    produce_prime();
    for (int i = 1; i <= n; ++ i) {
        if (b[i] == i)  continue;
        vector<int> r = get(b[i] - i + 1, 0);
        if (r.size() == 1) {
            ans.push_back(make_pair(i, b[i]));
            change(i, b[i]);
            continue;
        }
        r.clear();
        r = get(b[i] - i + 2, 0);
        if (r.size() == 2) {
            int x = b[i] + 1 - r[0];
            ans.push_back(make_pair(x, b[i]));
            ans.push_back(make_pair(i, x));
            change(x, b[i]);
            change(i, x);
            continue;
        }
        r.clear();
        r = get(b[i] - i + 3, 1);
        int x = b[i] + 1 - r[0];
        int y = x + 1 - r[1];
        ans.push_back(make_pair(x, b[i]));
        ans.push_back(make_pair(y, x));
        ans.push_back(make_pair(i, y));
        change(x, b[i]);
        change(y, x);
        change(i, y);
    }
    cout << ans.size() << endl;
    int size = (int)ans.size();
    for (int i = 0; i < size; ++ i) {
        cout << ans[i].first << " " << ans[i].second << endl;
    }
    return 0;
}

int main()
{
    cout << fixed << setprecision(16);
    ios :: sync_with_stdio(false);
    return MAIN();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值