bzoj1011 遥远的行星

bzoj1011 遥远的行星


原题链接


题解

一道真正的玄学题。。。。
其实这题根本没法做
首先暴力这么跑:$$ans(s)=\sum_{i=1}^{\lfloor As\rfloor}\frac{M_sM_i}{s-i}$$
暴力复杂度\(O(n^2)\)
虽然跑不满,但常数至少\(\frac{0.35}{2}\)
所以玄学做法才能过。。。
有一句话“只要结果的相对误差不超过5%即可.”
而且样例输出还提醒了你。
那么对于一段\([l,r]\),和点\(s\),

\[\sum_{i=l}^{r}\frac{M_sM_i}{s-i}$$, 可以近似看作 $$\sum_{i=l}^{r}\frac{M_sM_i}{s-\frac{l+r}{2}}\]

\(r-l\)不大的话误差就不大,所以把\([1,\lfloor As\rfloor]\)分成很多个区间,每个区间长为C(C设多少都可以,我设的80,只要不T不WA就行了),用上面方法算这些区间,剩下的就爆算。


Code

// It is made by XZZ
#include<cstdio>
#include<algorithm>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0;rg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}
#define db long double
#define eps 1e-6
const int maxn=1e5+2;
db M[maxn],S[maxn];
int main(){
    int n=gi(),C=30;
    db A;
    scanf("%Lf",&A);
    rep(i,1,n)scanf("%Lf",&S[i]),M[i]=M[i-1]+S[i];
    rep(s,1,n){
	db prt=0;
	int lim=(int)(A*s+eps),k=lim/C;
	rep(i,1,k)prt+=(M[i*C]-M[i*C-C])/(s-(i*C+i*C-C+1)*0.5);
	rep(i,k*C+1,lim)prt+=S[i]/(s-i);
	printf("%.10Lf\n",prt*S[s]);
    }
    return 0;
}
posted @ 2017-09-06 09:49  菜狗xzz  阅读(134)  评论(0编辑  收藏  举报