洛谷P1966
传送门
这是一道洛谷上的小蓝题,本蒟蒻想到最后一步就崩掉了。
下面就好好聊聊此题的思想:
首先先放AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int mod=1e8-3;
const int MAXN=1e5+5;
int n;
int d[MAXN],tre[MAXN];
int lowbit(int x)
{return x&-x;}
ll find_tre(int t)
{
ll kase=0;
for(int i=t;i>0;i-=lowbit(i))
{
kase=(kase%mod+tre[i]%mod)%mod;
}
return kase%mod;
}
void ADD_tre(int t)
{
for(int i=t;i<=n;i+=lowbit(i))
tre[i]++;
}
struct AC
{
int v,num;
friend bool operator < (AC m1,AC m2)
{
return m1.v<m2.v;
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
AC s1[MAXN],s2[MAXN];
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s1[i].v;
s1[i].num=i;
}
for(int i=1;i<=n;i++)
{
cin>>s2[i].v;
s2[i].num=i;
}
sort(s1+1,s1+1+n);
sort(s2+1,s2+1+n);
for(int i=1;i<=n;i++)
{
d[s1[i].num]=s2[i].num;
}
ll kase=0;
for(int i=1;i<=n;i++)
{
ADD_tre(d[i]);
kase=(kase%mod+(i-find_tre(d[i]))%mod)%mod;
}
cout<<kase%mod<<endl;
return 0;
}
初解此题,我很快想到要使其距离最短,就要保证他们的相对位置相同。
举个例子:
原始数组:
A1 1 3 2 4
A2 4 7 1 3
重新排序:
A1 1 2 3 4
A2 1 3 4 7
离散化:
A1 1 2 3 4
A2 1 2 3 4
原始数组离散化:
A1 1 3 2 4
A2 3 4 1 2
现在我们可以发原始问题转换为:如何移动数字,使得原始数组离散化后 A1[ i ]=A2[ i ] 。
这样想想,仿佛问题可以,或者说有机会直接暴力求解。(事实上,动手打代码就各种WA )
所以这时候就要将问题进一步转换。
再将 原始数组离散化 后的数组重新排序
A1 1 2 3 4
A2 3 1 4 2
这里提出一个问题:这样重新排序后的数组会影响转移次数吗?(这个问题我想了很久,一直想搞出一个数学证明来,但因为我是蒟蒻,就无了,所以只能口嗨一下思路)
可以这样考虑:
重新排序的意义实际上是构建了一个A1 和 A2之间的映射,即1 对应 3 ,2 对应 1 … 而此题的根本目的是通过移动使得1 对应 1,2 对应 2,所以只用再排完序之后使A2升序就行,而每次只能相邻之间移动使得此题可以通过找逆序对来计算。
(映射大法好!本蒟蒻根本想不到zzzzz )