Link
Solve
一道非常好的思维题。
直接统计非常难,需要用类似容斥的想法优化一道
最后的答案
(=1324-1432-1243)
(=(1x2x-1423)-(14xx-1423)-(12xx-1234))
(=1x2x-14xx-12xx+1234)
(=1x2x-1xxx+13xx+1234)
((x)表示排名任意,但是不能重复)
于是我们思考如何算出(1x2x,1xxx,13xx,1234)
先预处理几个数组(L_i,R_i)
(L_i=sum_{j<i}[y_j<y_i],R_i=sum_{j>i}[y_j<y_i]),用树状数组维护出来就好了
接下来看分别怎么求
1xxx
比较简单,对于每个(i)后面三个数乱取,就是(sum C_{n-i-R_i}^3)
1234
枚举(3)后面的个数就是(n-i-R_i),如果(2)的位置确定了,那么(1)的方案数就是(L_j),所以答案就是(sum_{i} (n-i-R_i)(sum_{j<i,y_j<y_i}L_j))
用树状数组来维护
1x2x
先枚举(2)的位置(i),那右边有(n-i-R_i)中方法,左边我们假设(1)的位置为(j),(2)的位置为(k)
左边要满足(j<k<i,y_j<y_i,y_k>y_i)
若只考虑(y_j<y_i,j<i,k<i),方案数是(L_i*(i-1))
那么就多算了(j<k,y_k<y_ij)和(j≥k)的方案
(j<k,y_k<y_ij)的方案数是(C_{L_i}^2)
(k≤j),对于每个(j),(k)的取值范围都是([1,j]),所以就是(sum_{p<i,y_p<y_i}p)
用树状数组维护
13xx
枚举(3),那么(4)有(n-i-R_i)种选法,(1,2)满足(j<i<k,y_j<y_k<y_i)
若只考虑(y_j<y_i,y_k<y_i,j<i)那么有(L_i ast(y_i-1))种选法,需要减去(k≤i)和(y_j>y_k)的方案数
(k≤i)是(C_{L_i}^2)
(y_kleq y_j),对于每个(j),(k)的取值都可以取到所有(y<y_j)的位置,每个(k)的取值范围为([1,p[j]])所以就是(sum_{p<i,y_p<y_i}y_p)
用树状数组维护
此题非常灵活的运用了树状数组,是个好题,好好看好好学,
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=200005;
const LL TT=16777216;
LL p[maxn],L[maxn],R[maxn],c[maxn],ans,N;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void add_x(int x,LL data){
for(int i=x;i<=N;i+=i&-i)c[i]=(c[i]+data)%TT;
return ;
}
int get(int x){
LL S=0;
for(int i=x;i;i-=i&-i)S=(S+c[i])%TT;
return S;
}
int main(){
freopen("P4528.in","r",stdin);
freopen("P4528.out","w",stdout);
N=read();
for(int i=1;i<=N;i++)p[i]=read();
for(int i=1;i<=N;i++)L[i]=get(p[i]),R[i]=p[i]-L[i]-1,add_x(p[i],1);
for(int i=1;i<=N;i++){
LL x=N-i-R[i];
ans=(ans-(x*(x-1)*(x-2)/6)%TT+TT)%TT;//1xxx
}
memset(c,0,sizeof c);
for(int i=1;i<=N;i++){
ans=(ans+(N-i-R[i])*get(p[i])%TT)%TT;//1234
add_x(p[i],L[i]);
}
memset(c,0,sizeof c);
for(int i=1;i<=N;i++){
ans=(ans+(L[i]*(i-1)-get(p[i])-(L[i]-1)*L[i]/2)*(N-i-R[i])%TT+TT)%TT;//1x2x
add_x(p[i],i);
}
memset(c,0,sizeof c);
for(int i=1;i<=N;i++){
ans=(ans+(L[i]*(p[i]-1)-(L[i]-1)*L[i]/2-get(p[i]))*(N-i-R[i])%TT+TT)%TT;//13xx
add_x(p[i],p[i]);
}
printf("%lld
",ans);
return 0;
}