zoukankan      html  css  js  c++  java
  • 卡片游戏 [逆序对_隐 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;
    }
    
  • 相关阅读:
    Java实现 LeetCode 69 x的平方根
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 66 加一
    Java实现 LeetCode 66 加一
    CxSkinButton按钮皮肤类
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822613.html
Copyright © 2011-2022 走看看