题意:
n(5*10^5)个不同的数字组成的序列a 寻找满足如下约束条件的数字组数: i1<i2<i3<i4 && ai1<ai2 && ai3<ai4
思路:
明显考察的是nlogn的算法 我们发现其实ai1和ai2可以放在一起考虑 同理ai3和ai4 这两组并没有相互影响
我们来看答案是怎么构成的 假设枚举i3的位置 那么我们希望知道“i3后面有几个数大于ai3” 这个可以通过树状数组处理
同理假设我们知道i2也希望知道“i2前面有几个数小于ai2” 这个也可以树状数组
那么再利用i3>i2 则答案就可以表示为 sum( num(>ai3) * sum( num(<ai2) ) )
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<map> #include<set> #include<vector> #include<queue> #include<cstdlib> #include<ctime> #include<cmath> using namespace std; typedef long long LL; #define N 50000 #define lowbit(x) (x&(-x)) inline void scand(int &ret) { char c; ret = 0; while ((c = getchar()) < '0' || c > '9') ; while (c >= '0' && c <= '9') ret = ret * 10 + (c - '0'), c = getchar(); } int t, n; int c[N + 10], d[N + 10], g[N + 10]; LL ans; void add(int f[], int x, int key) { while (x <= N) { f[x] += key; x += lowbit(x); } } int sum(int f[], int x) { int res = 0; while (x) { res += f[x]; x -= lowbit(x); } return res; } struct node { int val, id; } nd[N + 10]; bool cmp1(node fa, node fb) { return fa.val < fb.val; } bool cmp2(node fa, node fb) { return fa.id < fb.id; } int main() { scand(t); while (t--) { scand(n); for (int i = 1; i <= n; i++) { scand(nd[i].val); nd[i].id = i; } sort(nd + 1, nd + n + 1, cmp1); memset(c, 0, sizeof (c)); memset(d, 0, sizeof (d)); for (int i = 1; i <= n; i++) { int tmp = sum(c, nd[i].id); add(c, nd[i].id, 1); add(d, nd[i].id, tmp); g[nd[i].id] = sum(c, nd[i].id - 1); } sort(nd + 1, nd + n + 1, cmp2); ans = 0; for (int i = 3; i <= n; i++) { int tmp = nd[i].val - 1; tmp = n - i - (tmp - g[i]); ans += (LL) (tmp) * sum(d, i - 1); } printf("%I64d\n", ans); } return 0; }
原文地址:http://blog.csdn.net/houserabbit/article/details/42062267