题解 UVA1428 【Ping pong】

题目链接:Link

Solution

\(x_i\) 表示从 \(a_1\)\(a_{i-1}\) 中比 \(a_i\) 小的数的个数, \(y_i\) 表示从 \(a_{i+1}\)\(a_n\) 中比 \(a_i\) 小的数的个数,则答案等于 $\sum_{k=1}^N x[i](n-i-y[i])+(i-x[i]-1)y[i] $

可以用树状数组动态维护。

贴代码:

#include<cstdio>
#include<cstring>
const int maxn=100005;
int T,n,r;
int a[maxn],b[maxn];
int lowbit(int x) { return x&-x; }
inline int sum(int x)
{
	int res=0;
	while(x>0)
	{
		res=res+b[x];
		x-=lowbit(x);
	}
	return res;
}
inline void add(int x,int d)
{
	a[x]=a[x]+d;
	while(x<=r)
	{
		b[x]=b[x]+d;
		x+=lowbit(x);
	}
}
inline void set(int x,int d) { add(x,d-a[x]); }
int v[maxn],x[maxn],y[maxn];
long long res;
int main()
{
#ifdef local
	freopen("pro.in","r",stdin);
#endif
	scanf("%d",&T);
	while(T-->0)
	{
		scanf("%d",&n);
		r=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&v[i]);
			if(v[i]>r) r=v[i];
		}
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=1;i<=n;i++)
		{
			set(v[i],1);
			x[i]=sum(v[i]-1);
		}
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=n;i>=1;i--)
		{
			set(v[i],1);
			y[i]=sum(v[i]-1);
		}
		res=0;
		for(int i=2;i<=n-1;i++) res=res//小心溢出!
									+(long long)x[i]*(n-i-y[i])
									+(long long)(i-x[i]-1)*y[i];
		printf("%lld\n",res);
	}
	return 0;
}
posted @ 2019-08-19 21:54  happyZYM  阅读(117)  评论(0编辑  收藏  举报