题目链接:戳这里
题意:
给长度为n的整数序列,求四元组(a, b, c, d)组合数,其中
a≠b≠c≠d
, a < b, c < d 且
Aa<Ab,Ac>Ad
。
(1<=n<=50000,0<=si<=109)
题解:
排除重复的情况,一共有 逆序对数*顺序对数 种,重复的情况有a = c, a= d, b = c, b = d四种, 减去即可;
ls[i]:i左边比s[i]小的数;
lg[i]:i左边比s[i]大的数;
rs[i]:i右边比s[i]小的数;
rg[i]:i右边比s[i]大的数;
ans=∑ni=1ls[i]∗∑ni=1lg[i]−∑ni=1(rg[i]∗rs[i]+lg[i]∗rg[i]+ls[i]∗rs[i]+lg[i]∗ls[i])
可以用树状数组求逆序数 复杂度O(nlogn), 两遍即可求出四个数组
因为可能有重复元素且整数范围
109
,先离散化处理
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 5e4+10;
struct node
{
int num, index;
};
bool cmp_num(const node &x, const node &y) {return x.num < y.num; }
bool cmp_index(const node &x, const node &y) {return x.index < y.index; }
int n;
node s[MAXN];
int a[MAXN];
int ls[MAXN], lg[MAXN], rs[MAXN], rg[MAXN];
inline int lowbit(int x) {return x & -x;}
void update(int i)
{
while(i <= n)
{
a[i] ++;
i += lowbit(i);
}
}
int query(int i)
{
int ans = 0;
while(i > 0)
{
ans += a[i];
i -= lowbit(i);
}
return ans;
}
int main(int argc, char const *argv[])
{
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
{
scanf("%d", &s[i].num);
s[i].index = i;
}
sort(s+1, s+n+1, cmp_num);
int ma = 1, tmp = s[1].num;
for(int i = 1; i <= n; i++)
{
if(s[i].num == tmp)
s[i].num = ma;
else
{
tmp = s[i].num;
s[i].num = ++ma;
}
}
sort(s+1, s+n+1, cmp_index); //可以再开个数组 不用再sort一次, 懒得改了
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; i++)
{
int &k = s[i].num;
update(k);
ls[i] = query(k-1);
lg[i] = i - query(k);
}
memset(a, 0, sizeof(a));
for(int i = n; i >= 1; i--)
{
int &k = s[i].num;
update(k);
rs[i] = query(k-1);
rg[i] = n - i + 1 - query(k);
}
LL sum = 0, g = 0, s = 0;
for(int i = 1; i <= n; i++)
{
sum += rg[i] * rs[i] + lg[i] * rg[i] + ls[i] * rs[i] + lg[i] * ls[i];
g += lg[i];
s += ls[i];
}
LL ans = s * g - sum;
printf("%I64d\n", ans);
}
return 0;
}