• 卡片游戏 [逆序对_隐 II]



    Solutionmathcal{Solution}

    O(N2) O(N^2) 暴力: O(N)O(N) 枚举 起点, O(N)O(N) 枚举以该起点为左端点的区间, 计算即可.

    对一个区间 [l,r][l, r], 设 SiS_i 表示前缀和,

    需要满足以下条件才能对答案贡献 11 :

    1. SrSl1rl+1>=Lfrac{S_r-S_{l-1}}{r-l+1}>=L,
    2. SrSl1rl+1<=Rfrac{S_r-S_{l-1}}{r-l+1}<=R.

    满足上述条件的总数量即为 AnsAns.
    满足 SrSl1rl+1>=Lfrac{S_r-S_{l-1}}{r-l+1}>=L, 的数量为 num1num_1,
    满足 SrSl1rl+1>Rfrac{S_r-S_{l-1}}{r-l+1}>R (此地不等价于SrSl1rl+1>=R+1frac{S_r-S_{l-1}}{r-l+1}>=R+1), 数量为 num2num_2 .
    Ans=num1num2Ans =num_1-num_2 . (相当于一个简单的容斥)

    所以只需考虑 num1,num2num_1, num_2 如何求即可.


    化简 条件1: SrSl1rl+1>=Lfrac{S_r-S_{l-1}}{r-l+1}>=L

    SrSl1>=L(rl+1)S_r-S_{l-1}>=L(r-l+1)
    SrSl1>=LrLl+L       .S_r-S_{l-1}>=Lr-Ll+L .

    将关于 ll , 关于 rr 的项 分开.

    SrLr>=Sl1L(l1)S_r-Lr>=S_{l-1}-L(l-1)

    Bi=SiLiB_i=S_i-L*i,
    num1=(B )num_1 = (B 的非严格顺序数对数量).

    同理 num2num_2 凭此方法求出, 进而 AnsAns 也就可以得到了.


    Additionmathcal{Addition}

    当以 LL 为参数时, 求 {Bi}{B_i} 数组的 非严格顺序数对 可转换为求 {Bi}{B_i}严格逆序数对 tmptmp, 再使用 总数对数 减去 tmptmp.
    当以 RR 为参数时, 求 {Bi}{B_i} 数组的 严格顺序数对 可转换为求 {Bi}{-B_i}严格逆序数对.

    求逆序对时 下标从 0 开始 . 因为下标 l1[0,N1]l-1∈ [0, N-1],.

    进行多次归并排序时一定要清空数组, 因为 B[0]B[0] 的值会改变.


    Codemathcal{Code}

    #include<bits/stdc++.h>
    #define reg register
    
    typedef long long ll;
    const int maxn = 500005;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            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;
    }
    
    int N;
    int L;
    int R;
    int A[maxn];
    ll B[maxn];
    ll sum[maxn];
    int tmp[maxn];
    
    ll mergesort(int l, int r){
            if(r <= l) return 0;
            int mid = l+r >> 1;
            int t1 = l, t2 = mid+1, t3 = l;
            ll s = mergesort(l, mid) + mergesort(mid+1, r);
            while(t1 <= mid && t2 <= r)
                    if(B[t2] < B[t1]){ 
                            s += mid - t1 + 1;
                            tmp[t3 ++] = B[t2 ++];
                    }else   tmp[t3 ++] = B[t1 ++];
            while(t1 <= mid)tmp[t3 ++] = B[t1 ++];
            while(t2 <= r)  tmp[t3 ++] = B[t2 ++];
            for(reg int i = l; i <= r; i ++) B[i] = tmp[i];
            return s;
    }
    
    int main(){
            freopen("game.in", "r", stdin);
            freopen("game.out", "w", stdout);
            N = read(); L = read(); R = read();
            ll Fen_mu = (1+1ll*N)*N >> 1;
            for(reg int i = 1; i <= N; i ++) A[i] = read(), sum[i] = A[i] + sum[i-1];
            for(reg int i = 1; i <= N; i ++) B[i] = sum[i] - L*i;
            ll num_1 = mergesort(0, N);
            for(reg int i = 1; i <= N; i ++) B[i] = R*i - sum[i];
            B[0] = 0;
            ll num_2 = mergesort(0, N);
            ll Ans = (Fen_mu-num_1) - num_2;
            if(!Ans) printf("0
    ");
            else if(Ans == Fen_mu) printf("1
    ");
            else{
                    ll gcd = std::__gcd(Ans, Fen_mu);
                    printf("%lld/%lld
    ", Ans/gcd, Fen_mu/gcd);
            }
            return 0;
    }
    
  • 相关阅读:
    BZOJ.1468.Tree(点分治)
    BZOJ.1935.[SHOI2007]Tree园丁的烦恼(CDQ分治 三维偏序)
    BZOJ.4319.[cerc2008]Suffix reconstruction(后缀数组 构造 贪心)
    BZOJ.3262.陌上花开([模板]CDQ分治 三维偏序)
    洛谷.3374.[模板]树状数组1(CDQ分治)
    BZOJ.4566.[HAOI2016]找相同字符(后缀数组 单调栈)
    POJ.3145.Common Substrings(后缀数组 倍增 单调栈)
    POJ.2774.Long Long Message/SPOJ.1811.LCS(后缀数组 倍增)
    POJ.1743.Musical Theme(后缀数组 倍增 二分 / 后缀自动机)
    UOJ.35.[模板]后缀排序(后缀数组 倍增)
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822614.html
Copyright © 2020-2023  润新知