返回顶部

SCUT - 79 - 博丽灵梦与DDOS攻击 - 常微分方程

https://scut.online/p/79

题意: DDOS 攻击的总流量值为 \(L\),寓所服务器的吞吐量为 \(d\)
博丽灵梦可以多次使用魔法消耗 DDOS 攻击的流量:
设当前剩余攻击流量为 \(l\) ,那么灵梦可以使用 \(l+d\) 的魔法值,将剩余攻击流量变为一个随机的浮点数 \(l' (0 \leq l' < l)\)
服务器具有吞吐量 \(d\) ,故一旦剩余攻击流量 \(l \le d\) 时,服务器会立即消耗掉所有攻击流量。
求对于当前流量 \(L\) ,灵梦需要使用的总魔法值的期望。

设当前攻击流量为 \(x(x>d)\) 时,消耗的魔法能力期望为 \(f(x)\) ,有

\[f(x)=x+d+\frac{1}{x}\int_0^xf(t)dt \]

两边乘 \(x\)

\[xf(x)=x^2+dx+\int_0^xf(t)dt \]

两边微分

\[f(x)+xf'(x)=2x+d+f(x) \]

\[f'(x)=2+\frac{d}{x} \]

两边积分

\[f(x)=2x+d \ln x +C \]

代入特殊值

\[\lim_{x \to {d^+}f(x)=2d \]

解得

\[C=-d \ln d \]

\[ f(x)=\left\{ \begin{array}{rcl} 0 && {0 \le x \le d} \\ 2x+d \ln x -d \ln d && {x > d} \\ \end{array} \right. \]

代码:

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

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    while(~scanf("%d", &T)) {
        while(T--) {
            double x, d;
            scanf("%lf%lf", &x, &d);
            if(x > d)
                printf("%.2f\n", 2.0 * x + d * log(x) - d * log(d));
            else
                printf("0.00\n");
        }
    }
}

因为精度要求不高,也可以转为整数模拟积分:

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

const int T = 500000;

double dp[5 * T + 100];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int u;
    scanf("%d", &u);
    while(u--) {
        double l, d;
        scanf("%lf%lf", &l, &d);
        memset(dp, 0, sizeof(dp));
        int L = l * T, D = d * T;
        double sum = 0;
        for(int i = D + 1; i <= L; ++i) {
            dp[i] = sum / (i - 1) + i + D;
            sum += dp[i];
        }
        printf("%.2f\n", dp[L] / T);
    }
    return 0;
}

当时自己想的那个代码恰好也是50万,不过多了一个ceil,导致误差:

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

const int T = 500000;

double dp;
double predp;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int u;
    scanf("%d", &u);
    while(u--) {
        double l, d;
        scanf("%lf%lf", &l, &d);
        int D = d * T;
        dp = 0.0;
        predp = 0.0;
        int L = ceil(l * T);
        for(int i = D + 1; i <= L; ++i) {
            dp = predp / (i - 1) + (d + i / (double)T);
            predp += dp;
        }
        printf("%.2f\n", dp);
    }
    return 0;
}

去掉无关的常数之后,20万的精度是足够了的。

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

const int T = 200000;

double dp;
double predp;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int u;
    scanf("%d", &u);
    while(u--) {
        double l, d;
        scanf("%lf%lf", &l, &d);
        int D = d * T;
        dp = 0.0;
        predp = 0.0;
        int L = l * T;
        for(int i = D + 1; i <= L; ++i) {
            dp = predp / (i - 1) + D + i;
            predp += dp;
        }
        printf("%.2f\n", dp / T);
    }
    return 0;
}
posted @ 2019-10-17 17:24  Inko  阅读(167)  评论(0编辑  收藏  举报