洛谷的一道原题,方法有很多,树状数组以及排序,对刚学树状数组的人来说用排序会比较好理解。
本题最重要的结论就是,要保证两个数组中相同位置的差最小,但是不一定两个数组中数值相同,所以只需要保证相同位置放的数都是当前数组中第i小的,也就是第一个数组里面第i小数和第二个数组中第i的数放的位置要相同,这个地方搞明白之后,只需要找到最小移动次数,这个时候就简单了用归并排序+逆序对即可。
- #include
- #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
- #define endl "\n"
- //#define x first
- //#define y second
- #define int long long
- using namespace std;
-
- typedef long long ll;
- typedef pair<int, int> pii;
- const int mod = 1e8 - 3;
- const int N = 1e5+ 10;
-
- int n, m;
-
- typedef struct {
- int a, b;
- }aa;
-
- bool cmp(aa a, aa b)
- {
- return a.a < b.a;
- }
-
- int s[N], f[N], g[N], sum;
-
- void merge_sort(int l, int r)
- {
- if(l >= r) return ;
- int mid = l + r >> 1;
- merge_sort(l, mid);
- merge_sort(mid + 1, r);
-
- int i = l, j = mid + 1, k = 0;
- while(i <= mid && j <= r)
- {
- if(s[f[i]] <= s[f[j]])
- g[k ++] = f[i ++];
- else
- {
- g[k ++] = f[j ++], sum += mid - i + 1;
- sum %= mod;
- }
-
- }
- while(i <= mid) g[k ++] = f[i ++];
- while(j <= r) g[k ++] = f[j ++];
- for(i = l, j = 0; i <= r; i ++, j ++)
- f[i] = g[j];
- }
- aa o[N], p[N];
- inline void sovle()
- {
-
- cin >> n;
- for(int i = 0; i < n; i ++) {
- cin >> o[i].a;
- o[i].b = i;
- }
-
- for(int i = 0; i < n; i ++) {
- cin >> p[i].a;
- p[i].b = i;
- }
-
- stable_sort(o, o + n, cmp);
- stable_sort(p, p + n, cmp);
-
- for(int i = 0; i < n; i ++)
- s[i] = p[i].b; // 找出来第二个数组中第i小的数的位置
- for(int i = 0; i < n; i ++)
- f[o[i].b] = i; // 找到第一个数组中每个位置都是第几小的
-
- merge_sort(0, n - 1);
- cout << sum << endl;
- }
- signed main(void)
- {
- IOS;
- int t = 1;
- // cin >> t;
- while(t --) sovle();
- return 0;
- }