Luogu4528 CTSC2008 圖騰 樹狀陣列
阿新 • • 發佈:2018-12-06
設$f_i$表示$i$排列的數量,其中$x$表示不確定
那麼$$ans=f_{1324}-f_{1432}-f_{1243}=(f_{1x2x}-f_{1423})-(f_{14xx}-f_{1423})-(f_{12xx}-f_{1234})$$
$$=f_{1x2x}-(f_{14xx}+f_{12xx})+f_{1234}$$
$$=f_{1x2x}-f_{1xxx}+f_{13xx}+f_{1234}$$
①$f_{1xxx}$用樹狀陣列求正序對
②$f_{1234}$四個樹狀陣列瞎搞
③$f_{1x2x}$,考慮列舉$2$的位置
設$l_i$表示滿足$j<i,a_j<a_i$的$j$的數量,$r_i$表示滿足$j>i,a_j<a_i$的$j$的數量
那麼右邊的$x$的取法就是$N-i-r_i$種
考慮左邊的$x$,考慮容斥。滿足$p<i,q<i,a_p<a_i$的有序數對$(p,q)$的數量有$l_i \times (i-1)$個,但是其中多算了:
a.$p<q , a_q<a_i$,個數有$C_{l_i}^2$個
b.$p \geq q$,個數有$\sum j[j < i,a_j<a_i]$種
④$f_{13xx}$,考慮列舉$3$的位置,那麼右邊的$4$的取法有$N-i-r_i$種
仍然考慮容斥。滿足$a_p<a_i , a_q < a_i , p < i$的個數為$(a_i-1) \times l_i$
考慮多算了什麼:
a.$a_q > a_p , q < i$,有$C_{l_i}^2$種
b.$a_q \leq a_p$,有$\sum a_j[j < i , a_j < a_i]$種
上面四種加起來就行了
#include<bits/stdc++.h> //This code is written by Itst using namespace std; inline int read(){ int a = 0; bool f = 0; char c = getchar(); while(c != EOF && !isdigit(c)){if(c == '-') f = 1; c = getchar(); } while(c != EOF && isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ '0'); c = getchar(); } return f ? -a : a; } const int MAXN = 200010 , MOD = 16777216; int num[MAXN] , N , sum; namespace calc{ int Tree[4][MAXN] , l[MAXN] , r[MAXN]; inline int lowbit(int x){ return x & -x; } inline void add(int ver , int dir , int num){ while(dir <= N){ (Tree[ver][dir] += num) %= MOD; dir += lowbit(dir); } } inline int get(int ver , int dir){ int sum = 0; while(dir){ (sum += Tree[ver][dir]) %= MOD; dir -= lowbit(dir); } return sum; } void calc_1xxx(){ for(int i = N ; i ; --i){ long long t = N - i - get(0 , num[i]); sum = (sum - t * (t - 1) * (t - 2) / 6 % MOD + MOD) % MOD; add(0 , num[i] , 1); } } void calc_1234(){ for(int i = 1 ; i <= N ; ++i){ sum = (sum + get(3 , num[i])) % MOD; add(3 , num[i] , get(2 , num[i])); add(2 , num[i] , get(1 , num[i])); add(1 , num[i] , 1); } memset(Tree , 0 , sizeof(Tree)); } void calcl(){ for(int i = 1 ; i <= N ; ++i){ l[i] = get(0 , num[i]); add(0 , num[i] , 1); } } void calcr(){ for(int i = N ; i ; --i){ r[i] = get(1 , num[i]); add(1 , num[i] , 1); } } void calc_1x2x(){ for(int i = 1 ; i <= N ; ++i){ long long times = N - i - r[i] , base = (1ll * l[i] * (i - 1) - 1ll * l[i] * (l[i] - 1) / 2 - get(2 , num[i])) % MOD; sum = (sum + times * base) % MOD; add(2 , num[i] , i); } } void calc_13xx(){ for(int i = 1 ; i <= N ; ++i){ long long times = N - i - r[i] , base = (1ll * l[i] * (num[i] - 1) - 1ll * l[i] * (l[i] - 1) / 2 - get(3 , num[i])) % MOD; sum = (sum + times * base) % MOD; add(3 , num[i] , num[i]); } } } int main(){ #ifndef ONLINE_JUDGE freopen("4528.in" , "r" , stdin); //freopen("4528.out" , "w" , stdout); #endif N = read(); for(int i = 1 ; i <= N ; ++i) num[i] = read(); calc::calc_1xxx(); calc::calc_1234(); calc::calcl(); calc::calcr(); calc::calc_1x2x(); calc::calc_13xx(); cout << sum; return 0; }