2008 北京区域赛
题意:
给你n个不同的数值,选择其中一个数a,然后从其两侧分别选择一个数,使得两侧这两个数的值一个比a大,一个比a小。
问你共有多少种这样的组合。
思路:
n的数据范围为100000,暴力找肯定会超时,很自然往nlogn复杂度的算法方向想。
这题跟之前做过的求逆序数一个原理。
先离散化,使得数据在1~n之间。
每插入一个数值b,先询问b之前有几个数已经插入,即可得出b左侧小于b的个数,那b左侧大于b的个数也可得出。
再逆着插入一遍,即可得出右侧的。
AC代码:
/* **********************************************
Created Time: 2014-10-8 16:36:01
File Name : cf.cpp
*********************************************** */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <fstream>
#include <cstring>
#include <climits>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <utility>
#include <sstream>
#include <complex>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <functional>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 20005;
int c1[MAXN], c2[MAXN], n;
int t1[MAXN][2], t2[MAXN][2];
struct PP
{
int v, rank;
}a[MAXN];
int lowbit(int x)
{
return x&(-x);
}
void init()
{
for(int i = 1;i <= n; i++)
c1[i] = c2[i] = 0;
for(int i = 1;i <= n; i++)
{
t1[i][0] = t1[i][1] = 0;
t2[i][0] = t2[i][1] = 0;
}
}
void add(int i, int val, int *c)
{
while(i <= n)
{
c[i] += val;
i += lowbit(i);
}
}
int sum(int x, int *c)
{
int res = 0;
while(x > 0)
{
res += c[x];
x -= lowbit(x);
}
return res;
}
bool cmp(PP t, PP p)
{
return t.rank < p.rank;
}
bool cmp2(PP t, PP p)
{
return t.v < p.v;
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
init();
cin>>n;
for(int i = 1;i <= n; i++)
{
cin>>a[i].v;
a[i].rank = i;
}
//
sort(a+1, a+n+1,cmp2);
int num = 1;
for(int i = 1;i <= n; i++)
a[i].v = num++;
sort(a+1, a+n+1, cmp);
//
//
for(int i = 1;i <= n; i++)
{
t1[i][0] = sum(a[i].v, c1);
t1[i][1] = i - t1[i][0]-1;
add(a[i].v, 1,c1);
}
for(int i = n;i >= 1; i--)
{
t2[i][0] = sum(a[i].v, c2);
t2[i][1] = n-i-t2[i][0];
add(a[i].v, 1, c2);
}
LL res = 0;
for(int i = 0;i < n; i++)
{
res += (LL)t1[i][0] * t2[i][1];
res += (LL)t1[i][1] * t2[i][0];
}
cout<<res<<endl;
}
return 0;
}