HDU 5147 Sequence II 枚举+树状数组

来源:互联网 发布:入门鼠标推荐 知乎 编辑:程序博客网 时间:2024/05/29 19:05
HDU 5147
题意:给出[1..n]的排列P,问有多少个四元组(a,b,c,d) 1<=a<b<c<d<=n 并且p[a]<p[b] ,p[c]<p[d].
令f[i]为以第i个数为结尾 其前面有多少个数比它小. pre[i]为f[i]的前缀和.
令h[i]为以第i个数为开头 其后面有多少个数比它大.
则枚举四元组的c,其贡献为pre[c-1]*h[c].
f[i],h[i]求法:从小到大枚举数 用BIT统计第i个数之前/后有多少个位置被标记即可. 

sb了..知道f[i]就能知道h[i], 比p[i]大的有n-p[i]个 在它之前有i-1-f[i] 之后有 n-p[i]-(i-1-f[i])

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=5e4+20;int a[N],c[N];ll f[N],h[N],pre[N],pos[N];int lowbit(int x){    return x&-x;}void update(int x,int val){    for(int i=x;i<N;i+=lowbit(i))        c[i]+=val;}int query(int x){    int res=0;    for(int i=x;i>0;i-=lowbit(i))        res+=c[i];    return res;}int main(){    int T,n;    cin>>T;    while(T--)    {        memset(c,0,sizeof(c));        memset(f,0,sizeof(f));        scanf("%d",&n);        for(int i=1;i<=n;i++)            scanf("%d",&a[i]),pos[a[i]]=i;        for(int i=1;i<=n;i++)        {            int p=pos[i];            f[p]=query(p);            h[p]=n-i-(p-1-f[p]);            update(p,1);        }        pre[0]=0;        for(int i=1;i<=n;i++)            pre[i]=pre[i-1]+f[i];        ll ans=0;        for(int i=1;i<=n;i++)            ans+=h[i]*pre[i-1];        printf("%lld\n",ans);    }    return 0;}


原创粉丝点击