D. Assumption is All You Need
-
题意:给你两个长度为\(n\)的数组\(A\)和\(B\),每次可以交换\(A\)中的逆序对,问你\(A\)能否通过操作得到\(B\)。
-
题解:从后往前遍历,贪心策略是,越大的数在越前面越好,首先\(A_i\)一定不大于\(B_i\),不然gg,先确定\(B_i\)在\(A\)中的位置\(p\),我们要交换\((a_p,a_i)\),但不能直接交换,否则\([p+1,i-1]\)这些位置上的数如果有大于\(a_i\)的,在交换之后就不能在移动到\(p\)这个位置了,这和我们的贪心策略相违背,所以我们在这个过程中需要不断地将最大的\(a_j(a_i<a_j<b_i,j\in[p+1,i-1])\)往前移,可以用后缀记录最大值,然后push进答案即可,具体的看代码应该就能理解了.
-
题解:
#include <bits/stdc++.h> using namespace std; #define PII pair<int,int> #define fi first #define se second #define pb push_back #define ll long long #define ull unsigned long long #define PLL pair<ll,ll> const int N=10000010; const int mod=1e9+7; const int INF=0x3f3f3f3f; int n; int pos[N],a[N],b[N]; int suf_mx[N]; vector<PII> ans; int main(){ int _; scanf("%d",&_); while(_--){ scanf("%d",&n); ans.clear(); for(int i=1;i<=n;++i) scanf("%d",&a[i]),pos[a[i]]=i; for(int i=1;i<=n;++i) scanf("%d",&b[i]); bool flag=true; for(int i=n;i>=1;--i){ if(a[i]==b[i]) continue; if(a[i]>b[i]){ flag=false; break; } int p=pos[b[i]]; for(int j=1;j<=n+1;++j) suf_mx[j]=0; suf_mx[i]=i; for(int j=i-1;j>=p;--j){ if(a[j]<b[i]){ if(a[j]>a[suf_mx[j+1]]) suf_mx[j]=j; else suf_mx[j]=suf_mx[j+1]; } else suf_mx[j]=suf_mx[j+1]; } while(p<i){ int x=p,y=suf_mx[p+1]; ans.pb({x,y}); swap(a[x],a[y]); pos[a[x]]=x; pos[a[y]]=y; p=suf_mx[p+1]; } } if(!flag) puts("-1"); else{ printf("%d\n",(int)ans.size()); for(auto w:ans) printf("%d %d\n",w.fi,w.se); } } return 0; }