描述
题解
这个题是 CF 的一个题,但不是原题,题目弱化了,数据强化了,一开始想着一个经典算法——使序列有序的最少交换次数,可是意志不坚定的我还是点开了评论区,发现这个要用贪心写,可是发现写来写去就是过不去,一直 TLE,后来用栈写(代码 One),需要右移的入栈,遇见左移的时候出栈交换移动,可是最后依然是 TLE 了……
后来我佐学姐用使序列有序的最少交换次数的代码的变种(代码 Two)提交过了,而我一开始竟然怕结果不是最优的,而直接放弃了这种写法,坑死了……这个题就是一个经典算法的变种~~~
代码
One:
// TLE
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
const int MAXN = 2e5 + 10;
int n;
int p[MAXN];
int s[MAXN];
int t[MAXN];
stack<pair<int, int> > spii;
int main(int argc, const char * argv[])
{
cin >> n;
for (int i = 1; i <= n; i++)
{
scanf("%d", p + i);
}
for (int i = 1; i <= n; i++)
{
scanf("%d", s + i);
t[s[i]] = i;
}
for (int i = 1; i <= n; i++)
{
p[i] = t[p[i]];
}
int res = 0;
for (int i = 1; i <= n; i++)
{
if (p[i] > i)
{
spii.push(make_pair(i, p[i]));
}
else if (p[i] < i)
{
int pos = spii.top().first;
res += i - pos;
swap(p[i], p[pos]);
spii.pop();
if (!spii.empty())
{
i = spii.top().first;
}
else
{
i = pos;
}
}
}
cout << res << '\n';
return 0;
}
Two:
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
int A[MAXN];
int B[MAXN];
bool vis[MAXN];
int abs(int a)
{
return a < 0 ? -a : a;
}
int main ()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", A + i);
}
int b;
for (int i = 1; i <= n; i++)
{
scanf("%d", &b);
B[b] = i;
}
for (int i = 1; i <= n; i++)
{
A[i] = B[A[i]];
}
ll ans = 0;
for (int i = 1; i <= n; i++)
{
if (vis[i])
{
continue;
}
ll sum = 0;
for (int j = i; !vis[j]; j = A[j])
{
sum += abs(j - A[j]);
vis[j] = true;
}
ans += sum / 2;
}
printf("%lld\n", ans);
return 0;
}