[BZOJ 1145] 图腾totem
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1145
Solution:
算是一道神题了吧
设 f(abcd)为:当选出的四个数相对大小关系为abcd时,有多少种选择方式
则 res = f(1324) - f(1243) -f(1432)
用拆分法转化此问题 :
f(1324) = f(1x2x) - f(1423)
f(1243) = f(12xx) - f(1234)
f(1432) = f(14xx) - f(1432)
所以res = f(1x2x) + f(1234) - f(12xx) - f(14xx)
= f(1x2x) + f(1234) + f(13xx) - f(1xxx)
预处理求出l[i],r[i]表示在i的左/右,比a[i]小的个数
可以先用树状数组求l[i],则r[i]=(a[i]-l[i]-1)
接下来对每一种情况分类讨论即可:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=2e5+10; const int MOD=16777215; int n,dat[MAXN],bit[MAXN],l[MAXN],r[MAXN]; void Update(int pos,int val) { while(pos<=n) bit[pos]+=val,pos+=pos&(-pos); } int Query(int pos) { int ret=0; while(pos) ret+=bit[pos],pos-=pos&(-pos); return ret; } int cal1()//1x2x { memset(bit,0,sizeof(bit));int ret=0; for(int i=1;i<=n;i++) ret=(ret+((1ll*(n-i-r[i])*(l[i]*(i-2)-Query(dat[i])-l[i]*(l[i]-1)/2))&MOD))&MOD, Update(dat[i],i-1); return ret; } int cal2()//1234 { memset(bit,0,sizeof(bit));int ret=0; for(int i=1;i<=n;i++) ret=(ret+(1ll*(n-i-r[i])*Query(dat[i])&MOD))&MOD, Update(dat[i],l[i]); return ret; } int cal3()//13xx { memset(bit,0,sizeof(bit));int ret=0; for(int i=n;i>0;i--) ret=(ret+(1ll*(n-r[i]-i)*(Query(dat[i])-r[i]*(r[i]-1)/2)&MOD))&MOD, Update(dat[i],dat[i]-1); return ret; } int cal4()//1xxx { memset(bit,0,sizeof(bit));int ret=0; for(int i=1;i<=n;i++) { int t=n-i-r[i]; ret=(ret+(1ll*t*(t-1)*(t-2)/6&MOD))&MOD; } return ret; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&dat[i]); l[i]=Query(dat[i]);r[i]=dat[i]-1-l[i]; Update(dat[i],1); } printf("%d",(cal1()+cal2()+cal3()-cal4()+MOD+1)&MOD); return 0; }
Review:
1、16777216是2的24次方
可以用按位与来优化mod
2、思路的借鉴:
一般此类序列性问题,当每一位都确定时反而难以求解
于是我们将确定转化为不确定来统一计算答案