jzoj6307-安排【归并排序】
正題
題目大意
一個目前序列,一個目標序列,每次可以選擇一個區間交換區間最大值和最小值。
詢問在345678345678345678步內將目前序列轉換回目標序列的方案(輸出該方案)。
解題思路
我們考慮歸并排序,對于兩個升序的序列,我們考慮如何合并為一個序列。
我們從中間往兩邊擴張,我們發現在我們可以找到一個kkk使得任意x≤kx\leq kx≤k有amid?k>amid+k+1a_{mid-k}>a_{mid+k+1}amid?k?>amid+k+1?
我們找到最大的kkk并讓i=mid?k,j=mid+k+1i=mid-k,j=mid+k+1i=mid?k,j=mid+k+1這時我們就有這樣的
我們就有這樣的一個序列,我們考慮將i~Midi\sim Midi~Mid和Mid+1~jMid+1\sim jMid+1~j翻轉(顯然可以做到)
然后再將i~ji\sim ji~j這段進行翻轉就有
然后這個時候必定有L~iL\sim iL~i中任意一個數都小于等于j~Rj\sim Rj~R中的數。
所以這個時候我們在將L~MidL\sim MidL~Mid以i?1i-1i?1為新的MidMidMid再次進行新的排序,然后Mid~RMid\sim RMid~R以jjj為新MidMidMid再次進行排序即可。
這時我們發現對于一次排序需要的次數約為nlog?2n2\frac{n\log^2 n}{2}2nlog2n?,可以通過本題。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5000; int n,a[N],x[N<<7],y[N<<7],tot,cnt; void solve(int l,int mid,int r) {if(mid<l||mid>=r||l==r) return;int i=mid,j=mid+1;while(i>l&&j<r&&a[i-1]>a[j+1]) i--,j++;if(i[a]>j[a]){for(int k=i,p=mid;k<p;k++,p--)swap(k[a],p[a]),x[++tot]=k,y[tot]=p;for(int k=mid+1,p=j;k<p;k++,p--)swap(k[a],p[a]),x[++tot]=k,y[tot]=p;for(int k=i,p=j;k<p;k++,p--)swap(k[a],p[a]),x[++tot]=k,y[tot]=p;solve(l,i-1,mid);solve(mid+1,j,r);}return; } void Merge(int l,int r) {if(l==r) return;int mid=(l+r)/2;Merge(l,mid);Merge(mid+1,r);solve(l,mid,r);return; } int main() {freopen("swap.in","r",stdin);freopen("swap.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&i[a]);Merge(1,n);cnt=tot;for(int i=1;i<=n;i++)scanf("%d",&i[a]);Merge(1,n);printf("%d\n",tot);for(int i=1;i<=cnt;i++)printf("%d %d\n",x[i],y[i]);for(int i=tot;i>cnt;i--)printf("%d %d\n",x[i],y[i]); }總結
以上是生活随笔為你收集整理的jzoj6307-安排【归并排序】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实况足球电脑配置要求(实况足球电脑配置)
- 下一篇: 怎么查看电脑配置win7(查看电脑配置w