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

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

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

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

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

于是我们定义一个块大小(siz),然后对于一个长(siz)的区间([i,i+siz-1]),且这个区间位于影响(F_j)的取值的区间([1,lfloor Aj floor])中,那么我们近似地认为它们的贡献之和为(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
",Query(1,mx,i)*m[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/xryjr233/p/BZOJ1011.html