P3198 [HNOI2008]遥远的行星
发现 $A$ 不大,又允许较大的误差,考虑乱搞
考虑求出每个位置的答案,因为有 $1e5$ 个位置,所以每个位置差不多可以计算 $100$ 次贡献
所以把每个可以贡献的位置尽量均匀分成 $100$ 个块,同一个块内答案一起算
本来一个位置的贡献是 $m[i]m[j]/(i-j)$ ,那现在一个块的贡献就可以看成 $m[i](sum[r]-sum[l-1])/(i-mid)$,就是把一段的贡献放在一起算,下标就取中位数
这样误差就在 $5\%$ 以内了..
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; typedef double db; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7,T=100; const db eps=1e-8; int n,a[N],sum[N]; db A,ans[N]; int main() { n=read(); scanf("%lf",&A); for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++) { int R=1.0*i*A+eps; if(!R) continue; if(R<=T) { for(int j=1;j<=R;j++) ans[i]+=1.0*a[i]*a[j]/(i-j); continue; } int l=1,r,p=R/T,t=R%T; for(int j=1;j<=T;j++) { r=l+p-(j>t); ans[i]+=1.0*a[i]*(sum[r]-sum[l-1])/(i-(l+r)/2); l=r+1; } } for(int i=1;i<=n;i++) printf("%.6lf\n",ans[i]); return 0; }