【题目大意】

给出$n$个三维向量,设当前向量长度为$L$,每次沿着向量等概率走$[0,L]$个长度。一个球每秒半径增加1个长度,直到覆盖位置,每秒耗能为球体积,求总耗能的期望。

设最后半径为R,那么求得就是$ \int_0^R \frac{4}{3}\pi x^3\, dx.$的期望。

$1 \leq n \leq 3000$

【题解】

也就是求$E(\frac{\pi}{3}R^4)$,问题在于怎么求$E(R^4)$。

先提供一种错误做法及其实现:

我们设向量为$\{p_n\}$,设$x_i$是$(0,1)$等概率随机的。

那么相当于求$E( (\sum_{i=1}^n p_ix_i)^4 )$。

拆出一个数,相当于

$E((\sum_{i=1}^{n-1} p_ix_i + p_nx_n)^4)$

二项式展开,得

$E( (\sum_{i=1}^{n-1}p_ix_i)^4 + 4(\sum_{i=1}^{n-1}p_ix_i)^3(p_nx_n) + 6(\sum_{i=1}^{n-1}p_ix_i)^2(p_nx_n)^2+4(\sum_{i=1}^{n-1}p_ix_i)(p_nx_n)^3 + (p_nx_n)^4)$

所以我们只要维护$p_ix_i$的1~4次方的期望就行了吗?

讲道理是的啊,但是这种做法是错的,只能在所有向量同向的时候是对的。

为什么呢?因为考虑期望中有向量和向量数乘的一项,比如$4(\sum_{i=1}^{n-1}p_ix_i)(p_nx_n)^3$,这是不支持结合律的!!!

所以。。是错的qwq

======================分割线======================

我们接下来讲正确的做法

我们考虑把向量分成三个坐标表示$(a_i,b_i,c_i)$。

求$E(R^4)$还可以看做$E( ((\sum_{i=1}^{n} a_ix_i)^2 + (\sum_{i=1}^{n} b_ix_i)^2 + (\sum_{i=1}^{n} c_ix_i)^2) ^2)$

这样好像正常多了,至少没有向量了。

设当前做到k,当前的$p = \sum_{i=1}^k a_ix_i$,$q = \sum_{i=1}^k b_ix_i$,$r = \sum_{i=1}^k c_ix_i$。

那么也就是求$E( (p^2+q^2+r^2)^2 ) = E(p^4+q^4+r^4+2p^2q^2+2p^2r^2+2q^2r^2)$

设f[x,i,j,k]表示加到第x个向量,$p^i * q^j * r^k$的期望。

那么根据期望的线性性,答案就是f[n,4,0,0]+f[n,0,4,0]+f[n,0,0,4]+2 * (f[n,0,2,2]+f[n,2,0,2]+f[n,2,2,0])

考虑转移,每次加入一个向量,我们试着把其中一项加入当前的$a_ix_i,b_ix_i,c_ix_i$(记为$p',q',r'$)。

$E((p+p')^2(q+q')^2) = E((p^2+2pp'+p'^2)(q^2+2qq'+q'^2)) = E(p^2q^2+ 2p^2qq' + p^2q'^2+2pq^2p' + 4pqp'q' + 2pp'q'^2 + q^2p'^2 + 2qp'^2q' + p'^2q'^2)$

可能已经发现了转移方式了

f[x,i,j,k] = f[x-1, i-A, j-B, k-C] * E(A, B, C) * C(i, A) * C(j, B) * C(k, C)

E(a,b,c)表示$p'^A * q'^B * r'^C$的期望,根据定义显然就是求$E(a_i^Ab_i^Bc_i^Cx_i^{A+B+C})$的期望。

这里$x_i$是$(0,1)$的变量,所以$E(x_i^p) = 1/(p+1)$。由于$x_i$和前面几个x都是互相独立的,所以这时候$E(AB) = E(A)E(B)$.

$a_i^Ab_i^Bc_i^C$都是常数,所以最后答案是$a_i^Ab_i^Bc_i^C / (A+B+C+1)$

然后就可以转移啦。。

复杂度O(n * 常数)

# include <math.h>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int M = 3e3 + 10;
const int mod = 1e9 + 7;
const ld pi = acos(-1.0);

int C[5][5], n;
ld f[2][5][5][5], E[5][5][5];
ld a[M], b[M], c[M], sa[M], sb[M], sc[M];

// E(R^4) = E( ((∑a_i*x_i)^2 + (∑b_i*x_i)^2 + (∑c_i*x_i)^2)^2 )
// p = ∑a_i*x_i, q = ∑b_i*x_i, r = ∑c_i*x_i
// E(R^4) = E( p^4 + q^4 + r^4 + 2p^2 q^2 + 2p^2 r^2 + 2q^2 r^2 )

// p = p + a_nx_n, q = q + b_nx_n, r = r + c_nx_n 

// E((a_nx_n) ^ A * (b_nx_n) ^ B * (c_nx_n) ^ C)

/*
e.g.
(p+p')^2(q+q'^2)
= (p^2+2pp'+p'^2)(q^2+2qq'+q'^2)
= p^2q^2 + 2p^2q * q' + p^2q'^2 + ...
*/


int main() {
//    freopen("find.in", "r", stdin);
//    freopen("find.out", "w", stdout);
    C[0][0] = 1;
    for (int i=1; i<=4; ++i) {
        C[i][0] = 1;
        for (int j=1; j<=i; ++j) C[i][j] = C[i-1][j] + C[i-1][j-1];
    }
    while(cin >> n) { 
        if(!n) continue;
        memset(f, 0, sizeof f); 
        int cur = 1, pre = 0;
        f[pre][0][0][0] = 1;
        double Alpha, Beta, L;
        for (int i=1; i<=n; ++i) {
            scanf("%lf%lf%lf", &Alpha, &Beta, &L);
            a[i] = L * cos(Beta) * cos(Alpha), b[i] = L * cos(Beta) * sin(Alpha), c[i] = L * sin(Beta); 
        }
        for (int i=1; i<=n; ++i) {
            sa[0] = sb[0] = sc[0] = 1;
            for (int j=1; j<=4; ++j) {
                sa[j] = sa[j-1] * a[i];
                sb[j] = sb[j-1] * b[i];
                sc[j] = sc[j-1] * c[i];
            }
            for (int i=0; i<=4; ++i)
                for (int j=0; i+j<=4; ++j)
                    for (int k=0; i+j+k<=4; ++k)
                        E[i][j][k] = sa[i] * sb[j] * sc[k] / (i+j+k+1);
            for (int i=0; i<=4; ++i)
                for (int j=0; i+j<=4; ++j)
                    for (int k=0; i+j+k<=4; ++k) { 
                        f[cur][i][j][k] = 0;
                        for (int x=0; x<=i; ++x) 
                            for (int y=0; y<=j; ++y)
                                for (int z=0; z<=k; ++z)
                                    f[cur][i][j][k] += f[pre][i-x][j-y][k-z] * E[x][y][z] * C[i][x] * C[j][y] * C[k][z];
                    }
            swap(pre, cur);
        }
        ld ans = f[pre][4][0][0] + f[pre][0][4][0] + f[pre][0][0][4] + 2.0 * (f[pre][2][2][0] + f[pre][2][0][2] + f[pre][0][2][2]);
        ans = ans / 3.0 * pi;
        printf("%.9lf\n", (double)ans);
    } 
    return 0;
}
View Code

相关文章:

  • 2022-01-19
  • 2021-05-29
  • 2021-12-22
  • 2021-06-11
  • 2021-08-11
  • 2021-08-14
  • 2022-03-01
  • 2021-12-17
猜你喜欢
  • 2022-01-14
  • 2022-01-05
  • 2021-11-10
  • 2021-05-24
  • 2021-10-09
  • 2021-08-06
  • 2021-06-10
相关资源
相似解决方案