IOI2011 ricehub

Task:
n块稻田,每块稻田一个位置pi,稻田位置可能重叠.现在可以设置一个米仓,一块稻田运送粮食的代价就是运送的距离,现在给出花费t,求出在t内最多能运送多少粮食.
n≤1e5,pi≤1e9,t≤2e15.

Solution:
假如米仓的位置确定,可以确定最后选中的答案一定是最接近米仓的一段区间.而且左右端点到米仓的距离会尽可能接近.
=>假如最后的区间确定,那么米仓的位置就是其中点.
那么就可以枚举这个区间(l,r),很容易就发现对于同一个l,r具有二分的性质.因此直接枚举一维+二分一维即可.复杂度O(nlogn)
当然尺取也可以解决.复杂度为O(n).

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<map>
#include<set>
#define ll long long 
#define y1 abcdedhf
#define pb push_back
using namespace std;
inline void rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<1)+(res<<3)+(c^48);
    while(c=getchar(),c>=48);
}
const int M=1e5+5;
ll m;
int ans=0;
int L,n,A[M];
ll sum[M];
bool chk(int st,int en){
    int mid=(st+en)>>1;//mid就是建立谷仓的地方 
    ll cost=1ll*A[mid]*(mid-st+1)-sum[mid]+sum[st-1]+sum[en]-sum[mid]-1ll*A[mid]*(en-mid);
    if(cost<=m){
        return true;
    }
    return false;
}
int main(){
    int i,j,k;
    rd(n);rd(L);cin>>m;
    for(i=1;i<=n;i++){
        rd(A[i]);
        sum[i]=sum[i-1]+A[i];
    }
    int r=1;
    for(i=1;i<=n;i++){//枚举左端点 
        while(r<=n&&chk(i,r))r++;
        ans=max(ans,r-i);
    }
    cout<<ans<<endl;
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页