HDU 4000 Fruit Ninja(树状数组求逆序对、正序对 应用)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41661919/article/details/86616531

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4000

题意:给出n个数的一组排列,n:1~1e5,问其中有几组满足关系x<y<z且Ax<Az<Ay的组合。

思路:

      拿到这题,首先肯定能想到和树状数组求逆序数相联系,但一直在正向考虑,中Ay前面比它小的数有多少,比它大的数有多少,然后乘法原理在减去那种不可行的情况,不过不容易对于不可行的情况,很难找出求解方案。

      所以,题解思路,从后往前找规律,对当前Ai,若其后面有能和Ai构成三角关系的两个数,无非Ax<Az<Ay或者Ax<Ay<Az(x<y<z),前者求出Ax后面有几个比其大的数然后 计算一个公差为一的等差数列的前n-1项和即可,后者求出Az前面有几个比它小的数,后面后几个比它大的数,直接相乘即可。

      注意在在Ai位置求的 差项是关于三个数中中间那个数的,但最终要求的答案通过交换律可以变为所有的加项相加-所有减项相加,所以在倒序遍历时尽管不能求出关于当前位置的减项,但其对最终答案的贡献不会被漏掉,会在前面求出。(这算是解出本题的关键,将最终结果表示的多项式通过交换律转化为容易求解出的形式)。

扩展:

       本题因为是1~n的一组排列,所以树状数组可以在1~1e5范围上建立,如果Ai的数据范围上升到1e9,这时就可以离散化一下。 

AC代码:

/** Wjunjie **/
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
#define LL long long
using namespace std;
const int N=2e5+100;
const int M=100001*2;
const int mod=1e8+7;
int c[N];
void add(int x,int n)
{
    for(;x<=n;x+=x&-x)c[x]+=1;
}
int ask(int x)
{
    LL ans=0;
    for(;x;x-=x&-x)ans+=c[x];
    return ans;
}
int a[N];
int pre[N];
int last[N];
int main()
{
    int cas=0;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        memset(c,0,sizeof(c));
        memset(pre,0,sizeof(pre));
        memset(last,0,sizeof(last));
        scanf("%d",&n);
        int maxs=-1;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            if(a[i]>maxs)maxs=a[i];

        }
        //在a【i】左边且比其小的数
        for(int i=1;i<=n;++i)
        {
            pre[i]=ask(a[i]);//这题不会有重复的数,不用考虑等于的问题;
            add(a[i],maxs);
        }

        memset(c,0,sizeof(c));
        LL ans=0;
        for(int i=n;i>0;--i)
        {
            last[i]=n-i-ask(a[i]);//不用考虑等于的情况
            add(a[i],maxs);//到处里long long 一下;
            ans=(ans+(LL)((LL)last[i]*(last[i]-1)/2)%mod-(LL)((LL)pre[i]*last[i])%mod)%mod;//注意一下mod运算不能乱模;
        }
        printf("Case #%d: %lld\n",++cas,ans);

    }
    return 0;
}

The end;

猜你喜欢

转载自blog.csdn.net/qq_41661919/article/details/86616531
今日推荐