问题描述
小v家有一条护栏,由n个木板组成。第i个木板的高度是a[i]。现在小镇上流行给护栏画矩形,所以小v也要在自家的护栏上画。若要在区间[x,x+k-1]这个区间画一个宽度为k的矩形(1<=x<=n-k+1),为了美观,高度一定是这个区间里高度最低的木板。现在小v有m个心中理想的宽度,第i个为ki,(ki与kj之间可能一样,1<=i<=n,1<=j<=n)他想知道对于每个ki,求矩形高度的期望。
输入格式
第一行一个整数n,表示木板的数目。第2行有n个数,第i个数ai表示第个木板的高度。第3行一个整数m。第4行有m个数,表示小v心中理想的第i个宽度ki
输出格式
输出m行实数,第i行表示宽度为ki的 矩形高度的期望,只要你的答案和正确答案的差的绝对值小于10的-9次方,你的答案将被视为正确。
样例输入
3
3 2 1
4
1 2 3 1
3 2 1
4
1 2 3 1
样例输出
2.000000000000000
1.500000000000000
1.000000000000000
2.000000000000000
1.500000000000000
1.000000000000000
2.000000000000000
数据规模和约定
1 ≤ n ≤ 10
6
1 ≤ a i ≤ 10 9
1 ≤ m ≤ 10 6
1 ≤ k i ≤ n
1 ≤ a i ≤ 10 9
1 ≤ m ≤ 10 6
1 ≤ k i ≤ n
长度N的序列,所有位置到权值不大于他的位置距离和是nlogn级的……这个很显然。
然后我们高度从小到大来求有哪些长度的区间高度是这个。
我们需要知道他左方和右方距离他最近的在他之前计算过的点在哪。
这个线段树可以logn解决……我写的二分加树状数组log^2n的……
然后枚举起点,这个枚举的范围在距离近的那边,然后发现是对一段区间加同一个数……而且最后问,那就等价于对前缀和操作。
之前证明了距离和是nlogn级的,所以这个操作的复杂度就均摊为nlogn。
然后最后O(1)回答询问就行了。
算法瓶颈在于线段树或者二分加树状数组部分……线段树的话是nlogn的……二分加树状数组nlog^2n……二分加树状数组常数比较小还给了8s是可以过的。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,i,j,k,l,r,mid,L,R,len,x;
int where[1000011],a[1000011],dl[1000011],tree[1000011];
long long s[1000011];
bool cmp(int x,int y)
{
return a[x]<a[y];
}
int lowbit(int x)
{
return x-(x&(x-1));
}
void ins(int x)
{
while (x<=n)
{
tree[x]++;
x+=lowbit(x);
}
}
int qsum(int x)
{
int ans=0;
while (x)
{
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
cin >> n;
for (i=1;i<=n;i++) cin >> a[i],dl[i]=i;
sort(dl+1,dl+n+1,cmp);
for (i=1;i<=n;i++)
{
l=1,r=dl[i];
while (l!=r)
{
mid=(l+r)/2;
if (qsum(dl[i])-qsum(mid-1)==0) r=mid;
else l=mid+1;
}
L=l;
l=dl[i],r=n;
while (l!=r)
{
mid=l+r-(l+r)/2;
if (qsum(mid)-qsum(dl[i]-1)==0) l=mid;
else r=mid-1;
}
R=r;
ins(dl[i]);
if (dl[i]-L<R-dl[i]) x=dl[i]-L+1,len=R-dl[i];
else x=R-dl[i]+1,len=dl[i]-L;
for (j=1;j<=x;j++)
s[j]+=a[dl[i]],s[j+len+1]-=a[dl[i]];
}
for (i=1;i<=n;i++)
s[i]+=s[i-1];
cin >> m;
for (i=1;i<=m;i++)
{
cin >> k;
printf("%.11f\n",s[k]/(double)(n-k+1));
}
return 0;
}