• 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
    ", sgn_num*ord_num - illegal_num);
            return 0;
    }
    
  • 相关阅读:
    一种通用的简易缓存设计方案
    SpringCloud接入Passport中台服务的FeignClient简易集成配置
    一种基于P2P技术的高效数据传输方式
    应用多环境部署和Redis高可用
    瑞金小吃
    前(单页面)后端完全分离的OAuth2授权和分享
    Session(数据)共享的前后端分离Shiro实战
    10万Http(单机和集群Server)Subscribe的可行性实验和压测
    2018年你应该了解的前端新技术
    js常见问题总结归纳
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822636.html
Copyright © 2020-2023  润新知