像这样的C题对自己来说才是最能提升思维的好题。
首先要知道这些数的组合都是从1-n,
要想对数进行排序,比如pos[i]=4(i位置的数值为4),比较容易能想到i和4直接交换,
题目要求每次交换(i,j)且(j-i+1)为素数,这地方卡住
其实可以利用哥德巴赫猜想(任一大于5的整数都可拆分为三个素数之和,任一大于2的偶数都可拆分为两个素数之和)
然后我们就可以贪心了,先把(j-i+1)拆分,
利用二分找到最接近(j-i+1)的素数然后把对应这个素数上位置的数与pos[i]交换,一直迭代下去。
附个代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define clr(x) memset(x,0,sizeof(x))
#define fp1 freopen("in.txt","r",stdin)
#define fp2 freopen("out.txt","w",stdout)
#define pb push_back
#define INF 0x3c3c3c3c
typedef long long LL;
typedef pair<int,int> pii;
#define N 100002
int p[N],a[N],b[N];
bool v[N];
vector<pii> ans;
int n,s;
void solve(int i,int j){
ans.push_back(pii(i,j));
b[a[i]]=j;
b[a[j]]=i;
swap(a[i],a[j]);
}
int main(){
int s = 0;
clr(v);
for(int i = 2;i <= N;i++) if(!v[i]){
p[s++] = i;
for(LL j = (LL)i*(LL)i;j <= N;j+=i) v[j] = 1;
}
int i, j;
scanf("%d",&n);
for (i = 1;i <= n;i++){
scanf("%d",&a[i]);
b[a[i]] = i;
}
for (i = 1;i <= n;i++){
while (b[i]!=i){
if (!v[b[i]-i+1]){
//printf("%d %d~\n", i, b[i]);
solve(i,b[i]);
}
else {
j=lower_bound(p,p+s,b[i]-i+1)-p-1;
//printf("%d %d!\n", b[i]-p[j]+1,b[i]);
solve(b[i]-p[j]+1,b[i]);
}
}
}
printf("%d\n",ans.size());
for (i = 0;i < ans.size();i++)
printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}