[每日一题] [NC14522] 珂朵莉的数列
题目大意:
给定一个数组,有N*(N+1)/2个子序列,这些子序列总共有多少个逆序对?
对于没个arr[i] > arr[j], i < j,在总个数的贡献是(i + 1) * (N - j)。所以基本就跟算逆序对个数这个问题是一样的,无非就是在merge的时候不是算个数的总和而是算(N - j)的总和。这里我偷懒,直接用sort进行了merge时的排序,照说应该用inplace_merge或者是手写一个merge之类的。所以我的时间复杂度是O(nlog^2(n)),应该是O(nlog(n))就可以了。
然后WA了无数次,只好看看大神们的题解,原来是爆long long,所以换成了__int128就果断AC了。
//#pragma GCC optimize(2) #include <bits/stdc++.h> typedef __int128 ll; inline ll kuaidu() { ll k = 0; char f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -1; for (; isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } char KX[100]; inline void kuaixie(ll x) { if (x == 0) return (void) (putchar('0')); ll tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { KX[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(KX[--cnt]); cout<<endl; } int N; #define MAXN 10000005 ll a[MAXN]; int idx[MAXN]; ll ans = 0; void helper(int l, int r) { if (l >= r) return; int m = LMID(l, r); helper(l, m); helper(m + 1, r); // Merge two indices. // For each i, want to know the sum of N - idx[j], s.t. a[idx[j]] < a[idx[i]]. int j = m + 1; ll sm = 0; FOR(i,l,m){ while (j <= r && a[idx[j]] < a[idx[i]]) { sm += N - idx[j]; ++j; } ans += ll(idx[i] + 1) * sm; } sort(idx + l, idx + r + 1, [](int i, int j) {return a[i] < a[j];}); } void doit() { ll rtn = 0; REP(i, N) { idx[i] = i; } ans = 0; helper(0, N - 1); kuaixie(ans); } int main(int argc, char* argv[]) { N = kuaidu(); REP(i, N) { a[i] = kuaidu(); } doit(); return 0; }