HDU 5792 World is Exploding
题意:
给出n代表序列的长度,接下来给出序列A。找出abcd满足abcd互不相等1<=a<b<c<d<=n的同时A[a]<A[b],A[c]>A[d],问这样的abcd有几个.
思路:先忽略四个数两两不相等的条件,那就是(,逆序对个数)乘上(顺序对个数)。例如{2,4,1,3},逆序对就是{(2,1),(4,1),(4,3)} ,顺序对就是{(2,4),(2,3),(1,3)},这样3*3=9,一共九个符合a<b && c>d的四元组。但其中有很多不合法的,对于t这个数,不合法情况的个数就是 (关于t的逆序对个数×关于t的顺序对个数),一一减去就是结果了。(不合法的规律多写几组便能找到)
输入:
4
2 4 1 3
4
1 2 3 4
输出:
1
0
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define MM(a,b) memset(a,b,sizeof(a));
#define inf 0x7f7f7f7f
#define FOR(i,n) for(int i=1;i<=n;i++)
#define CT continue;
#define PF printf
#define SC scanf
const int mod=1000000007;
const int N=1e6+10;
int tmp[N],a[N],n,m,c[N],pos[N];
ll lmin[N],rmin[N],lmax[N],rmax[N];
int lowbit(int i)
{
return i&(-i);
}
void add(int x)
{
while(x<=m)
{
c[x]+=1;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x>0)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&tmp[i]);
a[i]=tmp[i];
}
sort(tmp+1,tmp+n+1);//将tmp按从小到大排序,用于树状数组查找顺/逆序对
m=unique(tmp+1,tmp+n+1)-tmp-1;//去重
for(int i=1;i<=n;i++)
pos[i]=lower_bound(tmp+1,tmp+m+1,a[i])-tmp;//找到原来的第i个数在排序后应在的位置
MM(c,0);
for(int i=1;i<=n;i++)//查询0-i-1之间比a[i]小的数放在lmin[i]里,在i-m之间比a[i]大的放在lmax里
{
lmin[i]=query(pos[i]-1);//
lmax[i]=query(m)-query(pos[i]);
add(pos[i]);
}
MM(c,0);
for(int i=n;i>=1;i--)//逆着再来一次
{
rmin[i]=query(pos[i]-1);
rmax[i]=query(m)-query(pos[i]);
add(pos[i]);
}
ll ans=0,l=0,r=0;
for(int i=1;i<=n;i++) {r+=rmax[i],l+=lmax[i];};
ans=l*r;
for(int i=1;i<=n;i++)//去除不合法的
{
ans-=lmin[i]*rmin[i];
ans-=lmax[i]*rmax[i];
ans-=lmax[i]*lmin[i];
ans-=rmax[i]*rmin[i];
}
printf("%lld\n",ans);
}
return 0;
}