USACO20OPEN Haircut G
Solution
不会做,于是参考题解
假设现在 \(\mathrm{John}\) 不再需要为肆意生长的头发而烦恼了,而是成为了一个因秃头而抓狂的脱发人士。现在,我们把理发看成是生发,那么第 \(i\) 根头发的极限长度就是 \(a_i\).
头发从 \(0\) 开始生长,在到达极限长度之前,每秒生长 \(1\) 个单位长度。现在我们把题目中的 \(j\) 看成是时间,那么第 \(j\) 秒头发最长一定不会超过 \(j\). 这不是正好符合题目限制吗?
显而易见的,第 \(0\) 秒的逆序对个数是 \(0\). 那么,我们现在需要考虑的是第 \(j\) 秒新增的逆序对。如果第 \(i\) 根头发的最大高度 \(a_i = j - 1\),说明第 \(j\) 秒它已经停止生长了。当 \(j-1\) 秒时,那些跟它比肩的小伙伴(指还未停止生长的头发)很可能借助从这一秒开始超过它。
也就是说,当满足 \(j < i\),\(a_j > a_i\) 时,从第 \(a_i + 1\) 秒开始,\(i\) 和 \(j\) 为答案贡献逆序对。观察前半句话,这还是个求逆序对,可以用树状数组维护;对于后半句话,就涉及区间加法了。因为这题不需要多次询问,因此直接差分即可。总时间复杂度 \(\mathrm{O(nlog_n)}\).
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
#define lowbit(x) (x & (-x))
using namespace std;
const int N = 2333333;
LL n, a[N], sum[N], t[N];
void add(LL x) { while(x <= n + 1) t[x]++, x += lowbit(x); }
LL query(LL x)
{
LL res = 0;
while(x) res += t[x], x -= lowbit(x);
return res;
}
int main()
{
scanf("%lld", &n);
memset(t, 0, sizeof(t));
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]), a[i]++;
sum[a[i] + 1] += query(n + 1) - query(a[i]);
add(a[i]);
}
for(int i = 1; i <= n; i++)
{
sum[i] += sum[i - 1];
printf("%lld\n", sum[i]);
}
return 0;
}