有 N ( 1 ≤ N ≤ 100 , 000 ) N(1\le N\le 100,000) N(1≤N≤100,000) 块地,每块地有 n ( 1 ≤ n ≤ 2000 ) n(1\le n\le2000) n(1≤n≤2000) 头牛。
在这些地之间建两个篱笆,这两个篱笆中间包含的是连续的地,使得该篱笆内平均每块地的牛数最多,每两个篱笆中间至少有 F ( 1 ≤ F ≤ N ) F(1\le F\le N) F(1≤F≤N) 块地。
这个题跟 HDU 2993 MAX Average Problem 斜率DP+IO优化 是一样的。
维护一个斜率单增的单调队列,找 i i i 的斜率最大对应点时从队列的开头进行判断。
代码如下(时间复杂度 O ( n ) O(n) O(n)):
#include<iostream>
#include<cstdio>
#include<algorithm>
//#define WINE
#define MAXN 100100
using namespace std;
int n,f,a[MAXN],s[MAXN],h,t,q[MAXN],res;
int up(int j,int k){
return s[j]-s[k];
}
int down(int j,int k){
return j-k;
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d%d",&n,&f);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
h=t=0;q[t++]=0;
for(int i=f;i<=n;i++){
while(h+1<t&&up(i,q[h])*down(i,q[h+1])<up(i,q[h+1])*down(i,q[h]))
h++;
res=max(res,(s[i]-s[q[h]])*1000/(i-q[h]));
int j=i-f+1;
while(h+1<t&&up(j,q[t-1])*down(q[t-1],q[t-2])<up(q[t-1],q[t-2])*down(j,q[t-1]))
t--;
q[t++]=j;
}
printf("%d\n",res);
return 0;
}
还可以用二分写:
#include<iostream>
#include<cstdio>
#include<algorithm>
//#define WINE
#define INF 0x3f3f3f3f
#define MAXN 100010
using namespace std;
int n,f,a[MAXN],Min=INF,Max=0;
double s[MAXN],l,r,mid,cur;
bool check(double k){
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i]-k;
double m=0;
for(int i=f;i<=n;i++){
cur=s[i]-m;
if(cur>=0)return true;
m=min(m,s[i-f+1]);
}
return false;
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d%d",&n,&f);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
Min=min(Min,a[i]);
Max=max(Max,a[i]);
}
l=Min;r=Max;
double eps=1e-5;
while(l+eps<r){
mid=(l+r)/2;
if(check(mid))l=mid;
else r=mid;
}
printf("%d\n",(int)(r*1000));
return 0;
}