• [bzoj2600][Ioi2011]ricehub_二分


    ricehub bzoj-2600 Ioi-2011

    题目大意:在数轴上有r块稻田,稻田坐标为整数。计划建造一个米仓,使得它可以收取尽量多的稻米。米仓的坐标仍需为整数。每一块权值为val的稻田距离米仓的距离为dis,那么收取这个稻田上的大米的代价是val*dis。我们只有b元运费,问最多能收取多少稻米。

    注释:$1le r le 10^5$,$1le lle 10^9$,$0le ble 2cdot 10^{15}$。

    想法:这就相当于在一个带权的数轴上选取一个点,使得所有点到该点的加权*距离最小。我们不妨将权值为val的点看成是val个不同的点。那么这就相当于在数轴上$sumlimits_{i=1}^{r}val_i$个点,所有点到被选取点的距离(由于已经将点拆过了,所以不加权)最小。显然,是在所有点的中位数(每一个点开成val个)的位置距离和最小。这样的话我们二分,对于每一个二分过程中的中间点check一下即可。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    int n,m,a[100005];
    ll tot,sum[100005];
    bool check(int x)
    {
        int j,mid,pos;
        for(int i=1;i+x-1<=n;i++)
        {
            j=i+x-1;
            mid=i+(x>>1)-1;
            pos=j-(x>>1)+1;
            if(sum[j]-sum[pos-1]-sum[mid]+sum[i-1]<=tot)
                return true;
        }
        return false;
    }
    int main()
    {
        scanf("%d%d%lld",&n,&m,&tot);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        int l=0,r=n;
        while(l+1<r)
        {
            int mid=(l+r)>>1;
            if(check(mid))
                l=mid;
            else r=mid-1;
        }
        if(check(r)) printf("%d
    ",r);
        else printf("%d
    ",l);
        return 0;
    }
    
    

    小结:对于加权的问题,我们可以将它拆掉,看成不加权的问题。

  • 相关阅读:
    select详解
    java Map及Map.Entry详解
    Java 基本类型
    java 获取String出现最多次数的字段
    java 居民身份证的校验
    java 删除文件
    Java 导出excel进行换行
    获取文件及其文件路径
    List<Map<String,Object>> 中文排序
    Java ----单个list 删除元素
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9103538.html
Copyright © 2020-2023  润新知