题意:给你n个数,然后在交换次数小于等于5×n的情况下使得这个序列变成升序,输出次数;
思路:哥德巴赫猜想:任何一个大于5的数都可以写成三个质数之和。尽可能的找大的素数,从1的位置向右逐步的调整,每一个位置最多5次,有的位置不到5次;
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #define maxn 100010 6 using namespace std; 7 8 int n; 9 int a[maxn+10]; 10 bool vis[maxn+10]; 11 int f[maxn+10]; 12 int p[maxn]; 13 int s[maxn*5],e[maxn*5]; 14 int cnt=0; 15 int bs(int x,int l,int r) 16 { 17 int pos=0; 18 while(l<r) 19 { 20 int mid=(l+r)/2; 21 if(f[mid]>x) 22 { 23 r=mid; 24 } 25 else 26 { 27 l=mid+1; 28 pos=l; 29 } 30 } 31 return pos; 32 } 33 void get_prime() 34 { 35 vis[1]=true; 36 vis[0]=true; 37 for(int i=2; i<maxn; i++) 38 { 39 if(!vis[i]) 40 { 41 for(int j=i*2; j<maxn; j+=i) 42 { 43 vis[j]=true; 44 } 45 } 46 } 47 for(int i=2; i<maxn; i++) 48 { 49 if(!vis[i]) 50 { 51 f[cnt++]=i; 52 } 53 } 54 } 55 56 int main() 57 { 58 get_prime(); 59 scanf("%d",&n); 60 for(int i=1; i<=n; i++) 61 { 62 scanf("%d",&a[i]); 63 p[a[i]]=i; 64 } 65 int ans=0; 66 for(int i=1; i<=n; i++) 67 { 68 while(a[i]!=i) 69 { 70 int t=bs(p[i]-i+1,0,cnt-1); 71 t--; 72 int sx=p[i],ex=p[i]-f[t]+1; 73 swap(a[sx],a[ex]); 74 swap(p[a[sx]],p[a[ex]]); 75 s[ans]=sx; e[ans++]=ex; 76 } 77 } 78 printf("%d\n",ans); 79 for(int i=0; i<ans; i++) 80 { 81 printf("%d %d\n",e[i],s[i]); 82 } 83 return 0; 84 }