• 【bzoj5090】组题 分数规划


    题目描述

    给出一个长度为n的序列,求一段长度大于等于k的字串,使得它们的平均值最大。

    输入

    第一行包含两个整数n,k(1<=n<=100000,1<=k<=n),分别表示题目的总量和题数的下界。

    第二行包含n个整数a_1,a_2,...,a_n(|a_i|<=10^8),分别表示每道题目的难度系数。

    输出

    输出一个既约分数p/q或-p/q,即平均难度系数的最大值。

    样例输入

    5 3
    1 4 -2 -3 6

    样例输出

    5/4


    题解

    分数规划

    二分答案mid,将每个数减去mid后,问题转化为判定性问题:是否存在一个长度大于等于k的字串,使得它们的和非负。

    把区间和转化为前缀相减的形式,求出前缀和。枚举区间右端点 $i$ ,要判定的就是 $sum[i]-min(sum[j])(0le jle i-k)$ 是否大于等于0。存在某一个大于等于0则有解,否则无解。

    但是答案询问的是分数形式怎么办?只需要每次记录答案的选择方式,最后根据这个方式再计算一遍即可。

    时间复杂度 $O(nlog n)$ 

    需要注意的一点是答案可能为负数,因此取gcd时需要取区间和的绝对值计算。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    using namespace std;
    typedef long long ll;
    int a[N] , n , k , ansl , ansr;
    double sum[N];
    ll gcd(ll a , ll b)
    {
        return b ? gcd(b , a % b) : a;
    }
    bool judge(double mid)
    {
        int i , pos = 0;
        for(i = 1 ; i <= n ; i ++ ) sum[i] = sum[i - 1] + a[i] - mid;
        for(i = k ; i <= n ; i ++ )
        {
            if(sum[i] - sum[pos] >= 0)
            {
                ansl = pos + 1 , ansr = i;
                return 1;
            }
            if(sum[i - k + 1] < sum[pos]) pos = i - k + 1;
        }
        return 0;
    }
    int main()
    {
        int i , cnt = 40;
        ll p = 0 , q , t;
        double l = 1 << 30 , r = -1 << 30 , mid;
        scanf("%d%d" , &n , &k);
        for(i = 1 ; i <= n ; i ++ )
        {
            scanf("%d" , &a[i]);
            l = min(l , 1.0 * a[i]) , r = max(r , 1.0 * a[i]);
        }
        while(cnt -- )
        {
            mid = (l + r) / 2;
            if(judge(mid)) l = mid;
            else r = mid;
        }
        q = ansr - ansl + 1;
        for(i = ansl ; i <= ansr ; i ++ ) p += a[i];
        t = gcd(p > 0 ? p : -p , q);
        printf("%lld/%lld
    " , p / t , q / t);
        return 0;
    }
    

     

  • 相关阅读:
    兜底方案只能用来兜底,而不能完全依靠它---记一次数据库唯一索引DuplicateKeyException异常的优化
    不注重开发细节,活该你忙!
    二叉树存储
    并查集模板
    684. 冗余连接
    820. 单词的压缩编码
    1102. 得分最高的路径
    滑动窗口模板
    古道西风“瘦马”
    西江月·凉凉
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8016811.html
Copyright © 2020-2023  润新知