Ping pong(POJ 3928)

测评传送门

题意:

T组数据,n个数,按顺序选出3个,求所有满足单调递增或单调递减的数对总和

Sample Input

1 
3 1 2 3

Sample Output

1

思路:

这道算是逆序对的高级做法,因为不只是单纯地去求一个逆序对

要求单调递减的数对,我们可以先按常规做法求出所有逆序对,但我们仔细想一下,这是谁的逆序对?

打表后你会发现,这是所有数的前缀逆序对,如果我们再把所有后缀逆序对求出,相乘不就是所有单调递减的数对了吗?

同理,顺序也如此

注意:

  不开long long 见祖宗,十年OI一场空

code

#include<stdio.h> 
#include<algorithm> 
#include<string.h>
#define lowbit(x) x&-x 
using namespace std;
const int mxn=20010;
struct node {
    int val,id;
}a[mxn];
bool operator <(const node &x,const node &y) {
    return x.val<y.val;
}
int n,f[mxn][2],c[mxn];

void add(int x) 
{
    while(x<=n) {
        c[x]++;
        x+=lowbit(x);
    }
}

int ask(int x) {
    int re=0;
    while(x) {
        re+=c[x];
        x-=lowbit(x);
    }
    return re;
}

int main() 
{
    int T;
    scanf("%d",&T);
    while(T--) {
        long long ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i) 
            scanf("%d",&a[a[i].id=i].val);
        sort(a+1,a+1+n);
        memset(c,0,sizeof(c));
        for(int i=n;i;--i) {
            add(a[i].id);
            f[i][0]=ask(a[i].id-1); //前逆序 
            f[i][1]=ask(n)-ask(a[i].id); //后顺对 
        }
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;++i) {
            add(a[i].id);
            ans+=f[i][1]*ask(a[i].id-1); //后顺*前顺 
            ans+=f[i][0]*(ask(n)-ask(a[i].id)); // 前逆序*后逆序 
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qseer/p/9857726.html