https://atcoder.jp/contests/nikkei2019-2-qual/tasks/nikkei2019_2_qual_c
比赛的时候D做出来了,然而C不知道怎么做 = =,用线段树去暴力找也WA了。
赛后看了几个人的代码,完全看不懂,像是for循环就写完了,应该是思维题,每天想一想,过了3天还是不会做
然后看了roundgod在评论区写的题解,看了半天看不懂,过了1天再配合代码看,终于领悟了,所以事实证明题目想不出要过段时间再想想,题解看不懂也可以过段时间再想想。
首先,把A,B排个序,如果排完序后的某个ai>bi,那么很显然是不行的。
然后,我们可以观察出N-2次交换,而对于1个序列,n-1次交换就一定能让他顺序完全正确,因为最差情况下最后一次交换也会使最后的两个位置同时正确,所以可以节约1次,也就是n-1次交换
所以如果拍完序后的某个aa[i+1]<=b[i] ,说明a[i]和a[i+1]之间的位置是无所谓的,那么这样也能节约一次交换,这种情况也是可行的,这里我思考花的时间最久,其实可以证明,我们把a[1]...a[i-1] a[i+2]...a[n]单独拿出来排,只要N-2次他们就归位了,剩下的a[i]和a[i+1]就不用排了,他们肯定在对应位置上或者交换位置。
最后。还要判断这些交换有几个环,由于不符合上述情况,即aa[i]<=bb[i] && aa[i+1]>bb[i],这样就说明a,b都是完全递增的,不存在数字相同的情况,所以可以离散化后把a[i]需要换到b[i]哪个位置求出来,然后如果这些交换形成了一个完整的环,那么就必须要n-1次交换,否则就会更少,环的数量为cnt,那么就只需要n-cnt次交换就行了,这题其实还可以加强。。。。
#include<bits/stdc++.h>
using namespace std;
const int maxl=1e5+10;
int n,ans;
int a[maxl],b[maxl],aa[maxl],bb[maxl],nxt[maxl];
map <int,int> mpa,mpb;
bool vis[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),aa[i]=a[i];
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),bb[i]=b[i];
}
inline void mainwork()
{
ans=0;
sort(aa+1,aa+1+n);
sort(bb+1,bb+1+n);
for(int i=1;i<=n;i++)
if(aa[i]>bb[i])
return;
for(int i=2;i<=n;i++)
if(aa[i]<=bb[i-1])
{
ans=1;
return;
}
for(int i=1;i<=n;i++)
mpa[aa[i]]=i,mpb[bb[i]]=i;
for(int i=1;i<=n;i++)
nxt[mpa[a[i]]]=mpb[b[i]];
int cnt=0;
for(int i=1;i<=n;i++)
if(!vis[i])
{
int u=i;cnt++;
while(!vis[u])
{
vis[u]=u;
u=nxt[u];
}
}
if(cnt>1)
ans=1;
}
inline void print()
{
if(ans)
puts("Yes");
else
puts("No");
}
int main()
{
prework();
mainwork();
print();
return 0;
}