[2019.1.7]BZOJ1011 [HNOI2008]遥远的行星

首先,我们都会暴力计算贡献。

我们还发现这题对精度的要求很低。

于是我们心想,这一定不是出题人随便放的,而是关乎正解的。

我们发现当\(j-i\)很大时,它的微小改变对答案的影响就是微不足道的。

于是我们定义一个块大小\(siz\),然后对于一个长\(siz\)的区间\([i,i+siz-1]\),且这个区间位于影响\(F_j\)的取值的区间\([1,\lfloor Aj\rfloor]\)中,那么我们近似地认为它们的贡献之和为\(\frac{\sum_{x=i}^{i+siz-1}M_x}{\frac{1}{2}[(j-i)+(j-i-siz+1)]}\)

也就是我们认为一个区间的\(j-i\)都是其中\(j-i\)的平均值。然后如果要求影响第\(j\)颗星球引力的星球区间\([1,x]\)的引力和,我们对它分块计算,对于小于\(siz\)的区间暴力计算。

然后就过了。

code:

#include<bits/stdc++.h>
using namespace std;
const double _=1e-8;
const int blk=40;
int n,mx;
double a,m[100010],sum[100010];
double query(int l,int r,int f){
	if(r<l)return 0;
	double st=((f-l)*1.0+(f-r)*1.0)/2.0;
	return (sum[r]-sum[l-1])/st;
}
double query1(int l,int r,int f){
	if(r<l)return 0;
	double ans=0;
	for(int i=l;i<=r;i++)ans+=m[i]/(f-i*1.0);
	return ans;
}
double Query(int l,int r,int f){
	if(r<l)return 0;
	double ans=0;
	while(r-l+1>=blk)ans+=query(l,l+blk-1,f),l+=blk;
	ans+=query1(l,r,f);
	return ans;
}
int main(){
	scanf("%d%lf",&n,&a);
	for(int i=1;i<=n;i++)scanf("%lf",&m[i]);
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+m[i];
	for(int i=1;i<=n;i++)mx=i*a+_,printf("%.5lf\n",Query(1,mx,i)*m[i]);
	return 0;
}
posted @ 2019-03-17 18:00  xryjr233  阅读(109)  评论(0编辑  收藏  举报