bzoj4476: [Jsoi2015]送礼物
考虑二分答案
对于一个区间一定是一边最大一边最小是最优的,还有不够补足L的情况,这个RMQ就好
枚举右端点是最大/最小,单调队列搞搞就完了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int _=1e2; const int maxn=5e4+_; const int mbit=30; int n,K,L,R,a[maxn]; namespace ST { int Bin[mbit],Log[maxn],mx[mbit][maxn],mn[mbit][maxn]; void main() { Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2; Log[1]=0;for(int i=2;i<=n ;i++)Log[i]=Log[i/2]+1; for(int i=1;i<=n;i++)mx[0][i]=mn[0][i]=a[i]; for(int j=1;Bin[j]<=n;j++) for(int i=1;i+Bin[j]-1<=n;i++) mx[j][i]=max(mx[j-1][i],mx[j-1][i+Bin[j-1]]), mn[j][i]=min(mn[j-1][i],mn[j-1][i+Bin[j-1]]); } int mxRMQ(int x,int y) { int k=Log[y-x+1]; return max(mx[k][x],mx[k][y-Bin[k]+1]); } int mnRMQ(int x,int y) { int k=Log[y-x+1]; return min(mn[k][x],mn[k][y-Bin[k]+1]); } double stu1() { double ans=0; for(int j=L;j<=n;j++) { ans=max(ans,(double)(mxRMQ(j-L+1,j)-mnRMQ(j-L+1,j))/(L-1+K)); } return ans; } } namespace DD { double em; namespace A { struct mnlist//单调减 { int head,tail,pos[maxn]; void clear(){head=1,tail=0;} void push_back(int x) { while(head<=tail&&(double)-a[pos[tail]]<=(double)-a[x]+em*(x-pos[tail]))tail--; pos[++tail]=x; } void pop_top(int lim){while(head<=tail&&pos[head]<=lim)head++;} int top(){return pos[head];} }A; bool check() { A.clear(); for(int j=L;j<=n;j++) { A.pop_top(j-R);//<=该决策点无效 A.push_back(j-L+1); int i=A.top(); if((double)(a[j]-a[i])+em*i>=em*(K+j))return true; } return false; } } //~~~~~~~~~~~~~~A~~~~~~~~~~~~~~~~~~~~ namespace B { struct mxlist { int head,tail,pos[maxn]; void clear(){head=1,tail=0;} void push_back(int x) { while(head<=tail&&(double)a[pos[tail]]<=(double)a[x]+em*(x-pos[tail]))tail--; pos[++tail]=x; } void pop_top(int lim){while(head<=tail&&pos[head]<=lim)head++;} int top(){return pos[head];} }B; bool check() { B.clear(); for(int j=L;j<=n;j++) { B.pop_top(j-R);//<=该决策点无效 B.push_back(j-L+1); int i=B.top(); if((double)(a[i]-a[j])+em*i>=em*(K+j))return true; } return false; } } //~~~~~~~~~~~~~~B~~~~~~~~~~~~~~~~~~~~ bool check(){return A::check()|B::check();} double stu2() { double el=0,er=1e8; while(er-el>1e-5) { em=(el+er)/2; if(check())el=em; else er=em; } return el; } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&n,&K,&L,&R); for(int i=1;i<=n;i++)scanf("%d",&a[i]); ST::main(); printf("%.4lf\n",max(ST::stu1(),DD::stu2())); } return 0; }
pain and happy in the cruel world.