Ping pong(POJ 3928)
Posted qseer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ",ans); } return 0; }
以上是关于Ping pong(POJ 3928)的主要内容,如果未能解决你的问题,请参考以下文章