原题
有个小点:吃甜甜圈不算一个步骤
有题易得,最优的步骤是确定了的:每次就找到最大的值,把其上的所有甜甜圈移动到另一边,然后吃掉最大的
为了加速这个过程,我们考虑将两堆甜甜圈顶部对接
这样,样例中的两组甜甜圈
1 4 5
2 7 3
变成了
5 4 1 || 2 7 3
将7吃掉的过程就变成了把那个竖杠移动到7的前面
5 4 1 2 ||7 3,斜杠变化前后中间隔着1个非零数(2)随后7被吃掉,把7设为0,现在是 5 4 1 2 || 0 3 花费步骤1
接下来要吃5,吃掉后变成0 || 4 1 2 0 3 两个竖杠前后隔着3个非零数(4,1,2),所以花费步骤3
接下来吃4,中间没有非零数, 0 || 0 1 2 0 3花费步骤0
接下来吃3 ,前后间隔两个非零数(1,2),花费步骤2
0 0 1 2 0 || 0
接下来吃2,中间无非0数,花费步骤0
吃1,中间无非0数,花费步骤0
故一共花费步骤6
现在问题就是如何快速求前后两个竖杠中间有多少非0数,可以用树状数组来处理这种前缀和问题
#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
//#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 100005;
PII a[N];
int n, m, ans;
int T[N];
int lowbit(int x) {
return -x & x;
}
void add(int x, int d) {
if (x > N)
return;
T[x] += d;
add(x + lowbit(x), d);
}
int find(int x) {
if (x <= 0)
return 0;
return T[x] + find(x - lowbit(x));
}
void solve() {
cin >> n >> m;
for (int i = n; i > 0; i--) {
add(i, 1);
cin >> a[i].x;
a[i].y = i;
}
for (int i = n + 1; i <= n + m; i++) {
add(i, 1);
cin >> a[i].x;
a[i].y = i;
}
a[n + m + 1].y = n;//在第一次找中心时,能正确地找到
sort(a + 1, a + n + m + 1);
for (int i = n + m; i >= 1; i--) {
int f = a[i + 1].y; //找到当前最大值位置
int t = a[i].y;//进行一次转移后,上一轮的i变成了中心
add(t, -1);
ans += abs(find(t) - find(f));
}
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}