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;
}

 

posted @ 2019-08-27 12:27  LLTYYC  阅读(132)  评论(0编辑  收藏  举报