栅栏
问题描述
家有一条栅栏,由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 }