栅栏

问题描述
家有一条栅栏,由n个木板顺序组成,第i个木板的高度是Ai。现在小镇上流行在栅栏
上画矩形,所以小v也要在自家的栅栏上画。若要在区间 [x,x+k-1] 这个区间画一个宽度为
k的矩形 (1≤x≤n-k+1) ,为了美观,高度一定是这个区间里高度最低的木板。现在小v心中
有m个理想的宽度,第i个为Ki,(Ki与Kj之间可能一样)。他想知道对于每个Ki,其矩形高度的
期望。
输入格式
第一行一个整数n,表示木板的数目。
第二行有n个正整数,第i个数表示第i个木板的高度。
第三行一个整数m,表示理想宽度的数目。
第四行有m个正整数,第i个数表示
心中理想的第i个宽度Ki。
输出格式
输出m行实数,第i行表示宽度为Ki的矩形高度的期望。答案保留5位小数。
样例输入输出
样例输入1
3
3 2 1
4
1 2 3 1样例输出1
2.00000
1.50000
1.00000
2.00000
限制与约定
对于100%的数据,

n<=1e6,m<=1e6,1<=Ai<=1e9,1<=Ki<=n

 

题解:

显然处理出L[i],R[i]表示左右第一个比i小的数,显然这个区间内跨越i的都是属于i的贡献

我们就处理L[i],R[i]之间端点,枚举i-L[i] 或 i-R[i] 显然处理较小的那个,然后差分加减即可

复杂度O(nlogn) 开始还以为和暴力是一样的..........................................................................

 

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #define ls (node<<1)
  8 #define rs (node<<1|1)
  9 using namespace std;
 10 typedef long long ll;
 11 const int N=1000005,INF=2e9;
 12 int gi(){
 13     int str=0;char ch=getchar();
 14     while(ch>'9' || ch<'0')ch=getchar();
 15     while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
 16     return str;
 17 }
 18 int a[N],n,m,ques[N],b[N],c[N],num=0,L[N],R[N];ll ans[N];
 19 namespace Deal1{
 20     int Tree[N<<2];
 21     void build(int l,int r,int node){
 22         if(l==r){
 23             Tree[node]=a[l];
 24             return ;
 25         }
 26         int mid=(l+r)>>1;
 27         build(l,mid,ls);build(mid+1,r,rs);
 28         Tree[node]=Tree[ls]<Tree[rs]?Tree[ls]:Tree[rs];
 29     }
 30     int query(int l,int r,int node,int sa,int se){
 31         if(l>se || r<sa)return INF;
 32         if(sa<=l && r<=se)return Tree[node];
 33         int mid=(l+r)>>1;
 34         int q1=query(l,mid,ls,sa,se),q2=query(mid+1,r,rs,sa,se);
 35         return q1<q2?q1:q2;
 36     }
 37     void main(){
 38         int k,tmp;
 39         build(1,n,1);
 40         for(int i=1;i<=num;i++){
 41             k=c[i];
 42             for(int j=1;j+k-1<=n;j++){
 43                 tmp=query(1,n,1,j,j+k-1);
 44                 ans[k]+=tmp;
 45             }
 46         }
 47         double ret;
 48         for(int i=1;i<=m;i++){
 49             ret=(double)ans[ques[i]]/(n-ques[i]+1);
 50             printf("%.5lf\n",ret);
 51         }
 52    }
 53 }
 54 namespace Deal2{
 55     int L[N],R[N],q[N];ll ans[N];
 56     void prework(){
 57         int r=1;q[0]=0;
 58         for(int i=1;i<=n;i++){
 59             while(1<=r && a[i]<a[q[r]])r--;
 60             L[i]=q[r]+1;q[++r]=i;
 61         }
 62         r=0;q[0]=n+1;
 63         for(int i=n;i>=1;i--){
 64             while(1<=r && a[i]<=a[q[r]])r--;
 65             R[i]=q[r]-1;q[++r]=i;
 66         }
 67     }
 68     void Getanswer(){
 69         int l,r;
 70         for(int i=1;i<=n;i++){
 71             l=i-L[i]+1;r=R[i]-i+1;
 72             if(l>r)swap(l,r);
 73             for(int j=1;j<=l;j++)
 74                 ans[j]+=a[i],ans[j+r]-=a[i];
 75         }
 76             for(int i=1;i<=c[num];i++)ans[i]+=ans[i-1];
 77     }
 78     void main(){
 79         prework();
 80         Getanswer();
 81         double ret;
 82         for(int i=1;i<=m;i++){
 83             ret=(double)(ans[ques[i]])/(n-ques[i]+1);
 84             printf("%.5lf\n",ret);
 85         }
 86     }
 87 }
 88 void work(){
 89     n=gi();
 90     for(int i=1;i<=n;i++)a[i]=gi();
 91       m=gi();
 92       for(int i=1;i<=m;i++)ques[i]=b[i]=gi();
 93       sort(b+1,b+m+1);
 94       for(int i=1;i<=m;i++)if(b[i]!=b[i+1])c[++num]=b[i];
 95     if(n<=2000)Deal1::main();
 96     else
 97     Deal2::main();
 98 }
 99 int main()
100 {
101     freopen("fence.in","r",stdin);
102     freopen("fence.out","w",stdout);
103     work();
104     return 0;
105 }

 

posted @ 2017-07-18 18:49  PIPIBoss  阅读(345)  评论(0编辑  收藏  举报