https://www.luogu.org/problem/show?pid=1419
题目描述
给定一个长度为n的序列a_i,定义a[i]为第i个元素的价值。现在需要找出序列中最有价值的“段落”。段落的定义是长度在[S,T]之间的连续序列。最有价值段落是指平均值最大的段落,
段落的平均值=段落总价值/段落长度。
输入输出格式
输入格式:
第一行一个整数n,表示序列长度。
第二行两个整数S和T,表示段落长度的范围,在[S,T]之间。
第三行到第n+2行,每行一个整数表示每个元素的价值指数。
输出格式:
一个实数,保留3位小数,表示最优段落的平均值。
输入输出样例
输入样例#1:
3 2 2 3 -1 2
输出样例#1:
1.000
说明
【数据范围】
对于30%的数据有n<=1000。
对于100%的数据有n<=100000,1<=S<=T<=n,-10000<=价值指数<=10000。
【题目来源】
tinylic改编
二分一个平均值,求出a[i]-x,在长度为[s,t]的区间的和为正,则说明x可以更小、
可以用单调递增队列维护编号在i-t,i-s的区间前缀和,则需判断sum[j]-sum[i]是否>=0
1 #include <cstdio> 2 3 inline void read(int &x) 4 { 5 register bool __=0; register char ch=getchar(); 6 for(; ch>‘9‘||ch<‘0‘; ch=getchar()) if(ch==‘-‘) __=1; 7 for(; ch>=‘0‘&&ch<=‘9‘; ch=getchar()) x=x*10+ch-‘0‘; 8 x=__?((~x)+1):x; 9 } 10 const int N(100000+5); 11 const int INF(10000); 12 int n,s,t,a[N]; 13 14 int head,tail,que[N]; 15 double l,r,mid,ans,sum[N]; 16 inline bool check(double x) 17 { 18 sum[0]=0; 19 for(int i=1; i<=n; ++i) sum[i]=sum[i-1]+a[i]-x; 20 head=1; tail=0; 21 for(int i=1; i<=n; ++i) 22 { 23 if(i>=s) 24 { 25 for(; head<=tail&&sum[i-s]<sum[que[tail]]; ) --tail; 26 que[++tail]=i-s; 27 } 28 if(head<=tail&&que[head]<i-t) head++; 29 if(head<=tail&&sum[i]-sum[que[head]]>=0) return 1; 30 } 31 return false; 32 } 33 34 int Presist() 35 { 36 read(n),read(s),read(t); 37 for(int i=1; i<=n; ++i) read(a[i]); 38 for(l=-INF*1.0,r=1.0*INF; l+1e-5<r; ) 39 { 40 mid=(l+r)/2.0; 41 if(check(mid)) l=mid; 42 else r=mid; 43 } 44 printf("%.3lf\n",l); 45 return 0; 46 } 47 48 int Aptal=Presist(); 49 int main(int argc,char*agrv[]){;}
时间: 2024-10-27 08:26:58