BZOJ 1145 图腾totem [算术计数][树状数组]

13 篇文章 0 订阅
5 篇文章 0 订阅

题目连接

f[1324]-f[1243]-f[1432]
=(f[1x2x]-f[1423])-(f[12xx]-f[1234])-
(f[14xx]-f[1423])
=f[1x2x]-f[12xx]+f[1234]-f[14xx]
=f[1x2x]+f[1234]-(f[14xx]+f[12xx])
=f[1x2x]+f[1234]-(f[1xxx]-f[13xx])

then

f[1xxx]:枚举(1)的位置i,直接计算
f[1234]:枚举(3)的位置i,则(4)的个数可算
预处理每个点左下角点的个数即可求出12的对数
f[1x2x]:枚举(2)的位置i,则(2)左边的【数字对】(a[x],a[y])(a[x]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 16777216
#define ll long long
const int N = 200010;
using namespace std;
int read(int &res){
    int flag=1;static char ch;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
    while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
int n,res;
int val[N];
ll l[N],r[N],c[N],cfr[N],cse[N],cth[N],cfu[N];
void add(int x,int v){
    for(register int i=x;i<=n;i+=i&-i)c[i]+=v;
}
ll query(int x,ll res=0){
    for(register int i=x;i;i-=i&-i)res+=c[i];return res;
}
void init(){
    for(register int i=1;i<=n;i++){
        l[i]=query(val[i]);
        r[i]=val[i]-l[i]-1;
        add(val[i],1);
    }
}
void addfr(int x,int v){
    for(register int i=x;i<=n;i+=i&-i)cfr[i]+=v;
}
ll queryfr(int x,ll res=0){
    for(register int i=x;i;i-=i&-i)res+=cfr[i];return res;
}
int FR(ll res=0){//1x2x
    for(register int i=1;i<=n;i++){
        res=(res+(l[i]*(i-1)-queryfr(val[i])-l[i]*(l[i]-1)/2)*(n-r[i]-i)+mod)%mod;
        addfr(val[i],i);
    }
    return res;
}
void addse(int x,int v){
    for(register int i=x;i<=n;i+=i&-i)cse[i]+=v;
}
ll queryse(int x,ll res=0){
    for(register int i=x;i;i-=i&-i)res+=cse[i];return res;
}
int SE(ll res=0){//13xx
    for(register int i=n;i;i--){
        res=(res+(queryse(val[i])-r[i]*(r[i]+1)/2)*(n-r[i]-i)+mod)%mod;
        addse(val[i],val[i]);
    }
    return res;
}
void addth(int x,int v){
    for(register int i=x;i<=n;i+=i&-i)cth[i]+=v;
}
ll queryth(int x,ll res=0){
    for(register int i=x;i;i-=i&-i)res+=cth[i];return res;
}
int TH(ll res=0){//1234
    for(register int i=1;i<=n;i++){
        res=(res+queryth(val[i])*(n-i-r[i])+mod)%mod;
        addth(val[i],l[i]);
    }
    return res;
}
int FU(ll res=0){//1xxx
    for(register int i=1;i<=n;i++){
        ll t=n-i-r[i];
        if(t>=3)
            res=(res+t*(t-1)*(t-2)/6+mod)%mod;
    }
    return res;
}
int main(){
    read(n);
    for(register int i=1;i<=n;i++)read(val[i]);
    init();
    printf("%d",(FR()+SE()+TH()-FU()+mod)%mod);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值