Tiny Counting[计数]

Tiny   CountingTiny\ \ \ Counting


Description


样例输入:
4
1 4 3 2
样例输出:
3


Solution

对每个数字 SiS_i, 可以将其在二维平面上表示

如图得到 SiS_i 与其他数字的 位置 的大小关系

  1. 第一象限 的数字与 SiS_i 构成以 SiS_i 为 第二项的 顺序对
  2. 第二象限 的数字与 SiS_i 构成以 SiS_i 为 第二项的 逆序对
  3. 第三象限 的数字与 SiS_i 构成以 SiS_i 为 第一项的 逆序对
  4. 第四象限 的数字与 SiS_i 构成以 SiS_i 为 第一项的 顺序对

每个数字都有 四个象限数字数量 的信息,
树状数组 维护各象限的 数字数量, 时间复杂度 O(NlogN)O(N*logN)


接下来是 计算答案 的方法

aabb 是顺序对, 数量为 sum1sum_1, ccdd 是逆序对, 数量为 sum2sum_2 .

 Temp=sum1sum2令\ Temp = sum_1 * sum_2, TempTemp 为总方案数量, 包括不合法方案 (a,b,c,da,b,c,d 重复的方案) .

在使用 TempTemp 逐个减去 不合法方案 :

  1. a=c=Sia = c = S_i, 此时 bb第四象限, dd第三象限 .
  2. a=d=Sia = d = S_i, 此时 bb第四象限, cc第二象限 .
  3. b=c=Sib = c = S_i, 此时 aa第一象限, dd第三象限 .
  4. b=d=Sib = d = S_i, 此时 aa第一象限, cc第二象限 .

对于 SiS_i (i[1,N]i ∈ [1, N]), TempTemp 需要减去

  1. LUiLDiLU_i * LD_i [ (a,b,c,da, b, c, d) == (t1,Si,t2,Sit_1, S_i, t_2, S_i)     t1SLu,  t2SLd\ \ \ \ t_1∈S_{Lu},\ \ t_2∈S_{Ld} ]
  2. LUiRUiLU_i * RU_i […]
  3. LDiRDiLD_i * RD_i […]
  4. RUiRDiRU_i * RD_i […]

其中 L,RL, R 表示左, 右, U,DU, D 表示大, 小;
合起来共同表示符合条件的数字数量

统计答案 时间复杂度 O(N)O(N)
最后 TempTemp 即是答案


Addition

Q: 为什么这样减去 不合法方案 会达到不重不漏的效果?
A: 这是因为每次减去的 不合法方案 都因 当前编号 重复而不合法,
在另一个位置时, 由于位置编号的唯一, 导致不合法的原因 一定不相同,
所以 不重不漏


Code

#include<bits/stdc++.h>
#define reg register

int read(){
        int s = 0, flag = 1;
        char c;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 1e5 + 50;
typedef long long ll;

int N;
int S[maxn];
int B[maxn];
int T[maxn];
int Lu[maxn], Ld[maxn];
int Ru[maxn], Rd[maxn];

void Modify(int k, int x){ while(k <= N) T[k] += x, k += k&-k; }
int Query(int k){ int s = 0; while(k > 0) s += T[k], k -= k&-k; return s; }
int Query_2(int l, int r){ return Query(r) - Query(l-1); }

int main(){
        N = read();
        for(reg int i = 1; i <= N; i ++) S[i] = read(), B[i] = S[i];
        std::sort(B+1, B+N+1);
        int Len = std::unique(B+1, B+N+1) - B-1;
        for(reg int i = 1; i <= N; i ++) S[i] = std::lower_bound(B+1, B+Len+1, S[i]) - B;
        for(reg int i = 1; i <= N; i ++){
                Ld[i] = Query_2(1, S[i]-1);
                Lu[i] = Query_2(S[i]+1, Len);
                Modify(S[i], 1);
        }
        memset(T, 0, sizeof T);
        for(reg int i = N; i >= 1; i --){
                Rd[i] = Query_2(1, S[i]-1);
                Ru[i] = Query_2(S[i]+1, Len);
                Modify(S[i], 1);
        }
        ll sgn_num = 0, ord_num = 0, illegal_num = 0;
        for(reg int i = 1; i <= N; i ++){
                sgn_num += Ru[i], ord_num += Rd[i];
                illegal_num += 1ll*Ru[i]*Rd[i] + 1ll*Ru[i]*Lu[i];
                illegal_num += 1ll*Ld[i]*Rd[i] + 1ll*Ld[i]*Lu[i];
        }
        printf("%lld\n", sgn_num*ord_num - illegal_num);
        return 0;
}
posted @ 2019-05-11 22:21  XXX_Zbr  阅读(228)  评论(0编辑  收藏  举报