HDU 4000 Fruit Ninjan 树状数组

版权声明:抱最大的希望,为最大的努力,做最坏的打算。 https://blog.csdn.net/qq_37748451/article/details/86622192

题意:给你一个长度为n的全排列,求有多少组(x,y,z)满足,x<y<z,且a【x】<a【z】<a【y】。

先求出满足,a【x】<a【z】,a【x】<a【y】有多少组,

对于当前点,后面有k个数比他大,那么有 k*(k-1)/2组。

我们在减去  a【x】<a【y】<a【z】的情况。

对于当前点,前面有k个数比他小,后面有u个数比他大,那么就有 k*u组。

利用树状数组来维护。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int MAXN=100000+5;
const int mod=100000007;
int n;
int c[MAXN],a[MAXN];//c[i]==A[i]+A[i-1]+...+A[i-lowbit(i)+1]
int num[MAXN];
int lowbit(int i)
{
    return i&(-i);
}
int sum(int x){
   int sum = 0;
    while(x){
        sum += c[x];
        x -= lowbit(x);
    }
    return sum;
}
void add(int x, int val){

    while(x <= n){
        c[x] += val;
        x += lowbit(x);
    }
}
int main()
{
	int t;
	scanf("%d",&t);
	int k=0;
	while(t--)
	{
		k++;
		scanf("%d",&n);
		memset(c,0,sizeof(c));
		memset(num,0,sizeof(num));
		ll sum1=0;
		ll sum2=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);

			num[a[i]]=sum(a[i]-1);
			ll t=n-a[i]+num[a[i]]+1-i;
			//cout<<a[i]<<" "<<t<<endl;
			sum1+=(t*(t-1)/2);
			add(a[i],1);
			if(i==1||i==n) continue;
			sum2+=((n-a[i]-i+num[a[i]]+1)*num[a[i]]);

		}
		ll ans=(sum1-sum2)%mod;
		printf("Case #%d: ",k);
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37748451/article/details/86622192