bzoj5055膜法师(离散化+树状数组)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj5055膜法师(离散化+树状数组)相关的知识,希望对你有一定的参考价值。

  传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=5055

  这道题……不得不说,从标题到题面都能看出一股浓浓的膜法气息……苟……

  题意就是统计顺序三元组(似乎可以这么叫吧)的乘积和。顺序三元组有个低阶版本叫做顺序对,顺序对有一个亲兄弟叫做逆序对。既然我们可以用值域树状数组来处理关于顺/逆序对,因此也可以尝试用同样的方法处理这道题。

  我们可以固定a[j],求剩下的a[i]和a[k]。ans=a[j]*sigma(a[i]*a[k])

  于是我们就把一个顺序三元组拆成了两个顺序对,一个是a[i]<a[j]且i<j,另一个是a[j]<a[k]且j<k,且这两个逆序对是不干扰的,可以直接把结果乘起来。

  所以我们对于每个数,求出左边比它小的数的总和,和右边比他大的数的总和,记为l[i]和r[i]。于是ans=sigma(a[i]*l[i]*r[i])

技术分享
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define mod 19260817
using namespace std;
inline ll read()
{
    ll tmp=0; char f=1,c=getchar();
    while(c<0||9<c){if(c==-)f=-1; c=getchar();}
    while(0<=c&&c<=9){tmp=tmp*10+c-0; c=getchar();}
    return tmp*f;
}
ll c[300010];
ll a[300010],id[300010],rk[300010];
ll l[300010],r[300010];
int n;
bool cmp(ll x,ll y){return a[x]<a[y];}
void add(int x,ll k){while(x<=n){c[x]+=k; x+=x&(-x);}}
ll getsum(int x){ll sum=0; while(x){sum+=c[x]; x-=x&(-x);} return sum;}
int main()
{
    int i;
    n=read();
    for(i=1;i<=n;i++)a[i]=read(),id[i]=i;
    sort(id+1,id+n+1,cmp);
    rk[id[1]]=1;
    for(i=2;i<=n;i++){
        rk[id[i]]=rk[id[i-1]];
        if(a[id[i]]>a[id[i-1]])++rk[id[i]];
    }
    for(i=1;i<=n;i++)c[i]=0;
    for(i=1;i<=n;i++){
        l[i]=getsum(rk[i]-1)%mod; add(rk[i],a[i]);
    }
    for(i=1;i<=n;i++)c[i]=0; ll sum=0;
    for(i=n;i;i--){
        r[i]=(sum-getsum(rk[i]))%mod; add(rk[i],a[i]); sum+=a[i];
    }
    ll ans=0;
    for(i=1;i<=n;i++)ans=(ans+l[i]*r[i]%mod*a[i])%mod;
    printf("%lld\n",ans);
    return 0;
}
bzoj5055

 

以上是关于bzoj5055膜法师(离散化+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ5055: 膜法师

bzoj5055: 膜法师(BIT)

bzoj 5055: 膜法师——树桩数组

[BZOJ5055]膜法师

BZOJ5055: 膜法师

bzoj5055 膜法师