• BZOJ2600_ricehub_KEY


    题目传送门

    这道题一开始我还以为是贪心,sort一遍直接取中点然后求最优值。

    但写了之后才发现错误,设置的谷仓只要是一段区间的中点即可。这段区间的两端一定是两片谷田。

    所以枚举区间的左端点,二分右端点,但问题是如何O(1)判断?

    设sumi表示1~i点的和。

    L~R区间所需要的费用分成两段来求。

    一段为L~mid-1,一段为mid+1~R。

    L~mid-1=a[mid]*(mid-l)-(sum[k-1]-sum[l-1]);

    mid+1~R=sum[r]-sum[k]-a[k]*(r-k);

    两者相加即为这段区间的费用总和。

    code:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    int read()
    {
        char c;while(c=getchar(),c<'0'||c>'9');int x=c-'0';
        while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
        return x;
    }
    
    int abs(int x){return x>0?x:-x;}
    
    const int MAXN=100005;
    
    int R,L,a[MAXN],i,ans;
    long long B,sum[MAXN];
    
    int find(int l,int r)
    {
        long long w=0,k=l+r+1>>1;
        w=a[k]*(k-l)-(sum[k-1]-sum[l-1])+sum[r]-sum[k]-a[k]*(r-k);
        return w<=B;
    }
    
    int check(int x)
    {
        int l=x,r=R,mid,tot;
            while(l<=r){
                mid=l+r>>1;
                if(find(x,mid))l=mid+1,tot=mid;
                else r=mid-1;
            }
        return tot-x+1;
    }
    
    int main()
    {
    //    freopen("x.txt","r",stdin);
        R=read(),L=read();scanf("%lld",&B);
            for(i=1;i<=R;i++)a[i]=read(),sum[i]=sum[i-1]+a[i];
            for(i=1;i<=R;i++){
                ans=max(ans,check(i));
            }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    代码 技术债务 打分
    C++ boost coroutine
    什么是 Python Django Flask &Tornado
    Quartz应用与集群原理分析
    和开源产品对比
    Apache Storm || Processing real-time data
    认清自我,不在迷茫 程序员
    快速傅里叶变换算法
    Netty和Tomcat的区别、性能对比
    HTTP vs. MQTT ->TCP
  • 原文地址:https://www.cnblogs.com/Cptraser/p/8320771.html
Copyright © 2020-2023  润新知