BZOJ-1011&洛谷P3198遥远的行星【HNOI2008】-玄学题之分块

Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge

洛谷:时间限制1.00s 内存限制125.00MB

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1011

洛谷:https://www.luogu.com.cn/problem/P3198

Description

  直线上N颗行星,X=i处有行星i,行星J受到行星I的作用力,当且仅当i<=AJ.此时J受到作用力的大小为 Fi->j=
Mi*Mj/(j-i) 其中A为很小的常量,故直观上说每颗行星都只受到距离遥远的行星的作用。请计算每颗行星的受力
,只要结果的相对误差不超过5%即可.

Input

  第一行两个整数N和A. 1<=N<=10^5.0.01< a < =0.35,接下来N行输入N个行星的质量Mi,保证0<=Mi<=10^7

Output

  N行,依次输出各行星的受力情况

Sample Input

5 0.3
3
5
6
2
4

Sample Output

0.000000
0.000000
0.000000
1.968750
2.976000

HINT

  精确结果应该为0 0 0 2 3,但样例输出的结果误差不超过5%,也算对


如果数据范围小一些的话就很好办,就是简单的暴力,我们先写出来:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int mac=1e5+10;

int m[mac];
double f[mac];

int main()
{
    int n;
    double a;
    scanf ("%d%lf",&n,&a);
    for (int i=1; i<=n; i++)
        scanf("%d",&m[i]);
    for (int i=1; i<=n; i++) f[i]=0;
    for (int i=1; i<=n; i++){
        for (int j=1; j<=(int)i*a; j++){
            f[i]+=1.0*m[i]*m[j]/(1.0*i-j);
        }
    }
    for (int i=1; i<=n; i++)
        printf("%f\n",f[i]);
    return 0;
}

然后交一发就会发现只过了2个点。

然后。。。怎么优化,发现好像不会,就无耻地打开了题解。。。神TM近似解。

按照题解的算法来讲就是分块,由于有5%的误差,所以我们可以用块的中点来代替整个块,块越大误差越大,那么块中的答案就是$\frac {m[i]\times \sum_{j=l}^{r}m[j]} {i-(l+r)/2}$

数列分块的具体方法在我以前的博客中有过说明:https://blog.csdn.net/qq_43906000/article/details/100435873

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

#define ll long long

const int mac=1e5+10;
const double esp=1e-5;

int m[mac],id[mac],L[mac],R[mac];
ll sum[mac];

double solve(int r,int p)
{
    int rr=id[r];
    double ans=0;
    if (rr==1){
        for (int i=1; i<=r; i++)
            ans+=(double)m[i]*m[p]/(p-i);
    }
    else{
        for (int i=1; i<=rr-1; i++)
            ans+=(double)m[p]*sum[i]/(p-(double)(R[i]+L[i])/2);
        for (int i=L[rr]; i<=r; i++)
            ans+=(double)m[p]*m[i]/(p-i);
    }
    return ans;
}

int main()
{
    int n;
    double a;
    scanf ("%d%lf",&n,&a);
    for (int i=1; i<=n; i++)
        scanf("%d",&m[i]);
    int len=pow(n,0.35)+esp;
    int t=n/len;
    for (int i=1; i<=t; i++){
        L[i]=(i-1)*len+1;
        R[i]=i*len;
    }
    if (R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
    for (int i=1; i<=t; i++)
        for (int j=L[i]; j<=R[i]; j++)
            id[j]=i,sum[i]+=m[j];
    for (int i=1; i<=n; i++){
        int r=i*a+esp;
        double ans=solve(r,i);
        printf("%lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lonely-wind-/p/12217361.html