对于 的计算,先计算把 移成连续段,然后再计算逆序对数(最小交换次数使得一个排列排好序)。
至于为什么是对的?感性理解一下,首先排好序一定要有个逆序对的代价,假如两个数之间没有相邻,则交换它们需要一步一步走过去,这样的花费就高了。
考虑 新增的代价,计算逆序对数是容易的, 只可能作为逆序对的第一个数,而第二个数可能的取值 都已经出现过,所以直接计算全局中以 为开头的逆序对数,树状数组易做到。
计算把 移成连续段的代价,有个经典结论就是移到中位数处,如果长度为偶数,移到中间两个的哪个都行。
因为每个数不能移动到同一位置,所以代价计算会很麻烦,那就钦点让每个数可以移动到同一位置,最后再减去多余代价也就是两个等差数列即可。
现在计算每个数移动到中位数处的距离,注意到每加入一个 之后中位数的最多会移动 个位置,且移动之后除了 以外的值对总代价的贡献不变,直接用 set
维护 出现的位置然后移动就可以了。
其实可以不用维护中位数,直接用树状数组记录哪些位置出现了数然后倍增找中位数也可以,常数更小。
代码可能不大像说人话的样子,看看思路就好了。
#include<iostream>
#include<cstdio>
#include<vector>
#include<set>
#define pb push_back
#define mp std::make_pair
#define fir first
#define sec second
typedef std::pair<int, int> pii;
typedef std::vector<int> veci;
typedef std::vector<pii> vecpii;
typedef long long ll;
ll Abs(ll x) { return x < 0 ? -x : x; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
inline int lowbit(int x) { return x & (-x); }
const int N = 2000100;
int n, a[N], pos[N];
struct BIT {
int tree[N];
int sumq(int x) { int sum = 0; for(; x; x -= lowbit(x)) sum += tree[x]; return sum; }
void modify(int x, int v) { for(; x <= n; x += lowbit(x)) tree[x] += v; }
}tr;
ll ans[N], c[N];
std::set<int>st;
ll calc(ll x) { return x * (x + 1) / 2; }
signed main() {
read(n);
for(int i = 1; i <= n; ++i) read(a[i]), pos[a[i]] = i;
for(int i = n; i; --i) {
c[a[i]] = tr.sumq(a[i]);
tr.modify(a[i], 1);
}
int p = 1, num = 1; st.insert(pos[1]);
for(int i = 2; i <= n; ++i) {
ans[i] = ans[i-1] + c[i];
if(!(i&1)) {
ans[i] += Abs(pos[num] - pos[i]);
if(pos[i] < pos[num]) ++p;
st.insert(pos[i]);
continue ;
}
st.insert(pos[i]);
if(pos[i] < pos[num]) ++p;
if(p != (i+1)/2) {
auto it = st.lower_bound(pos[num]);
if(pos[i] < pos[num]) --it, --p;
else ++it, ++p;
num = a[*it];
}
ans[i] += Abs(pos[num] - pos[i]);
}
for(int i = 1; i <= n; ++i) printf("%lld ", ans[i] - calc((i-1)/2) - calc(i/2));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?