当前位置: 代码迷 >> 综合 >> #树状数组#[ssloj 1474] 简单计算题 [jzoj] Tiny Counting
  详细解决方案

#树状数组#[ssloj 1474] 简单计算题 [jzoj] Tiny Counting

热度:51   发布时间:2024-02-10 18:14:05.0

Title

在这里插入图片描述


Solution

假如 a , b , c , d a,b,c,d 可以相等,那么 a n s ans 是顺序对和逆序对的乘积。可以减去不合法的的方案数。
l s , l b , r s , r b ls,lb,rs,rb 指的是比分别左边比 i i 小的,大的,右边比 i i 小的,大的的数量。
排除以下四种情况:

  • a = c a=c
  • S d < S a = c < S b S_d<S_{a=c}<S_b
  • ( a = c ) < b , d (a=c)<b,d
  • r s ? r b rs*rb

  • a = d a=d
  • S c > S a = d < S b S_c>S_{a=d}<S_b
  • c < ( a = d ) < b c<(a=d)<b
  • l b ? r b lb*rb

  • b = c b=c
  • S a < S b = c > S d S_a<S_{b=c}>S_d
  • a < ( a = c ) < d a<(a=c)<d
  • l s ? r s ls*rs

  • b = d b=d
  • S a < S b = d < S c S_a<S_{b=d}<S_c
  • a , c < ( b = d ) a,c<(b=d)
  • l b ? l s lb*ls

以第一和第二种情况举例:
第一种
在这里插入图片描述
第二种
在这里插入图片描述


Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define rep(i,x,y) for(register ll i=x;i<=y;i++)
using namespace std; 
ll n,ans,t[100500],a[100500],b[100500],p,q,ls[100005],lb[100005],rs[100005],rb[100005]; 
inline void add(ll x,ll y){for(;x<=n;x+=x&(-x)) b[x]+=y;}
inline ll ask(ll x){ll q=0; for(;x;x-=x&(-x)) q+=b[x]; return q;}
int main(){scanf("%lld",&n); rep(i,1,n) scanf("%lld",&a[i]),t[i]=a[i]; sort(t+1,t+n+1); int m=unique(t+1,t+n+1)-t-1; rep(i,1,n) a[i]=lower_bound(t+1,t+m+1,a[i])-t; rep(i,1,n){ls[i]=ask(a[i]-1); lb[i]=ask(n)-ask(a[i]); p+=ls[i]; add(a[i],1); }memset(b,0,sizeof(b)); for(int i=n;i>=1;i--){rs[i]=ask(a[i]-1); rb[i]=ask(n)-ask(a[i]); q+=rs[i]; add(a[i],1); }rep(i,1,n) ans=p*q; rep(i,1,n) ans-=ls[i]*rs[i]+rs[i]*rb[i]+rb[i]*lb[i]+lb[i]*ls[i]; printf("%lld",ans); return 0; 	
}