当前位置: 首页 > article >正文

2024 icpc 第二场网络赛题解

比赛链接:https://qoj.ac/contest/1799

A. Gambling on Choosing Regionals

题意

n n n 个队伍, k k k 个赛站,对于第 i i i 个赛站,一个学校最多能派 c i c_i ci 个队伍参加这个赛站。

i i i 个队伍的能力值大小为 w i w_i wi,所属学校为 s i s_i si

一个队伍可以参加两个赛站,能力大小越大,队伍的排名越前,题目保证队伍的能力大小各不相同。

问在最坏的情况下,每个队伍的最小排名是多少?

数据范围

1 ≤ n , k ≤ 1 0 5 , 1 ≤ c k ≤ 1 0 9 , 1 ≤ ∣ s i ∣ ≤ 10 1 \le n,k \le 10^5,1 \le c_k \le 10^9,1 \le |s_i| \le 10 1n,k105,1ck109,1si10

思路

先来理解这个最坏情况是什么?
这个最坏情况指的是一个队伍参加比赛,会有尽可能多的队能力值比该队伍大, 从而使得这个队伍排名变大。

对于特定的队伍,能力值比这个队伍大的队伍的数量是固定的,而每个赛站同一个学校派出的最大队伍数是不一样的,所以影响队伍排名大小的是选择的赛站。

显然,选择 c i c_i ci 前二小的赛站是最优的,因为赛站越小,能力值比当前队伍大的队伍能参加的越少。

因为一个队伍能参加两个赛站,所以有多少个比当前队伍能力值大的队伍参加了 c i c_i ci 次小的赛站,这些队伍也能选择参加 c i c_i ci 最小的赛站,使得当前队伍的排名最大化。

可是,也可能存在同校的问题,使得在 c i c_i ci 最小的赛站,比当前队伍能力值大的队伍有部分无法参加,因此,参加 c i c_i ci 最小的赛站获得的最小排名,就是当前队伍在最坏情况下能获得的最小排名。

可以把队伍按能力值大小从大到小排序,从前往后遍历队伍,同时记录当前遍历的队伍为止,所有的学校对应的队伍出现次数。

因为考虑的是 c i c_i ci 最小的赛站,所以每个学校对应的队伍出现次数上界是 m i n ( c i ) ( 1 ≤ i ≤ k ) min(c_i)(1 \le i \le k) min(ci)(1ik),如果到达上界则该学校对应的队伍出现次数不再增加。

因为当前遍历的队伍必然排在前面的队伍之后,所以若遍历第 i i i 个队伍,所有学校的队伍的出现次数为 c n t cnt cnt,那么第 i i i 个队伍的可能最小排名即为 c n t cnt cnt

复杂度

时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn),空间复杂度 O ( n ) O(n) O(n)

代码实现

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

#define int long long
#define fs first
#define sc second

typedef pair<array<int, 2>, string> PAS;

const int N = 1e5 + 5;

int n, k;
int ans[N];
vector<PAS> arr;
unordered_map<string, int> cnt;

void solve()
{
    cin >> n >> k;
    int cm = 1e9;
    for (int i = 1; i <= k; i++) {
        int ci;
        cin >> ci;
        cm = min(cm, ci);
    }
    for (int i = 1; i <= n; i++) {
        int w;
        string s;
        cin >> w >> s;
        arr.push_back({ { w, i }, s });
    }
    sort(arr.begin(), arr.end(), greater<PAS>());

    int cur = 0;
    // 记录遍历到当前队伍,总的队伍出现次数(在cm的限制下)
    for (auto it : arr) {
        int id = it.fs[1];
        string s = it.sc;
        if (cnt[s] < cm) {
            cur++;
            cnt[s]++;
        }
        ans[id] = cur;
    }
    for (int i = 1; i <= n; i++) {
        cout << ans[i] << '\n';
    }
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

F. Tourist

题意

初始分数为 1500 1500 1500,有 n n n 次分数变动,第 i i i 次分数变动为增加 c i c_i ci 分。

问在第几次分数变动后,分数不低于 4000 4000 4000 分?

如果不存在输出 − 1 -1 1

数据范围

1 ≤ n ≤ 1 0 5 , 0 ≤ ∣ c i ∣ ≤ 1 0 9 1 \le n \le 10^5,0 \le |c_i| \le 10^9 1n105,0ci109

思路

按题意模拟即可。

复杂度

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

代码实现

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

#define int long long

void solve()
{
    int n;
    cin >> n;

    int cur = 1500;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        cur += x;
        if (cur >= 4000) {
            cout << i;
            return;
        }
    }
    cout << "-1";
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

G. Game

题意

起初 A l i c e Alice Alice x x x 个石子, B o b Bob Bob y y y 个石子。
游戏会进行若干轮, A l i c e Alice Alice 赢一轮的概率为 p 0 p_0 p0 B o b Bob Bob 赢一轮的概率为 p 1 p_1 p1,两人平局的概率为 1 − p 0 − p 1 1-p_0-p_1 1p0p1

如果两人平局,则什么都不发生,进入下一轮。
否则,如果赢家的石子数不小于输家的石子数,则赢家赢得整场游戏的胜利;如果赢家的石子数小于输家的石子数,那么输家的石子数会减少和当前赢家石子数相同的数量,然后进入下一轮。
A l i c e Alice Alice 赢得整场游戏的胜利的概率是多少?
(答案要对 998244353 998244353 998244353 取模)

数据范围

1 ≤ T ≤ 1 0 5 , T 为数据组数 1 \le T \le 10^5,T为数据组数 1T105,T为数据组数
1 ≤ x , y ≤ 1 0 9 1 \le x,y \le 10^9 1x,y109
1 ≤ a 0 + a 1 ≤ b < 998244353 1 \le a_0+a_1 \le b < 998244353 1a0+a1b<998244353,表示 p 0 = a 0 b , p 1 = a 1 b p_0 = \frac{a_0}{b},p_1 = \frac{a_1}{b} p0=ba0,p1=ba1

思路

因为平局是不会影响当前状态的,所以不需要考虑平局的情况,此时要么赢要么输,赢的概率变为 q 0 = p 0 p 0 + p 1 = a 0 b a 0 b + a 1 b = a 0 a 0 + a 1 q_0 = \frac{p_0}{p_0+p_1} = \frac{\frac{a_0}{b}}{\frac{a_0}{b}+\frac{a_1}{b}}=\frac{a_0}{a_0+a_1} q0=p0+p1p0=ba0+ba1ba0=a0+a1a0,同理输的概率变为 q 1 = p 1 p 0 + p 1 = a 1 a 0 + a 1 q_1 = \frac{p_1}{p_0+p_1} = \frac{a_1}{a_0+a_1} q1=p0+p1p1=a0+a1a1

如果当前 x ≥ y x \ge y xy B o b Bob Bob 需要赢 ⌊ x y ⌋ \lfloor \frac{x}{y}\rfloor yx 局才能使得 x < y x <y x<y,那么 A l i c e Alice Alice 获胜的情况要么 B o b Bob Bob x ( 0 ≤ x < ⌊ x y ⌋ ) x(0 \le x < \lfloor \frac{x}{y}\rfloor) x(0x<yx⌋) 轮后, A l i c e Alice Alice 再赢一轮,对应的概率为 q 0 ∑ i = 0 ⌊ x y ⌋ − 1 q 1 i = q 0 ∗ ( 1 − q 1 ⌊ x y ⌋ 1 − q 1 ) q_0\sum_{i=0}^{\lfloor \frac{x}{y}\rfloor -1}q_1^i = q_0*(\frac{1-q_1^{\lfloor \frac{x}{y}\rfloor}}{1-q_1}) q0i=0yx1q1i=q0(1q11q1yx),要么是以 q 0 ⌊ x y ⌋ q_0^{\lfloor \frac{x}{y}\rfloor} q0yx 的概率转换到 x < y x<y x<y 的状态( x x x 变成 x m o d    y x \mod y xmody y y y 不变),然后 A l i c e Alice Alice 最终获胜。

如果当前 x < y x<y x<y,只要 B o b Bob Bob 赢一轮, B o b Bob Bob 就获胜了,只有 A l i c e Alice Alice 连续赢 ⌊ y x ⌋ \lfloor \frac{y}{x}\rfloor xy 局,转换到 x ≥ y x \ge y xy 的状态,才会存在 A l i c e Alice Alice 获胜的情况,转换到 x ≥ y x \ge y xy 的状态( x x x 不变, y y y 变成 y m o d    x y \mod x ymodx)的概率为 p 0 ⌊ y x ⌋ p_0^{\lfloor \frac{y}{x}\rfloor} p0xy

可以发现,在 A l i c e Alice Alice 获胜概率的求解过程中, x ≥ y x \ge y xy x < y x<y x<y 的状态是交替转换的,但是 x , y x,y x,y 会一直减小,所以可以用一个变量 a n s ans ans 记录 A l i c e Alice Alice 的获胜概率,直到到达 x = 0 x=0 x=0 或者 y = 0 y=0 y=0 的状态为止。

如果 x = 0 x=0 x=0,说明此时 B o b Bob Bob 获胜了。
如果 y = 0 y=0 y=0,说明此时 A l i c e Alice Alice 获胜了,如果到达当前状态的概率为 c u r cur cur,则 A l i c e Alice Alice 存在 c u r cur cur 的概率获胜,把 c u r cur cur 加到 a n s ans ans 中。

如果到达 x ≥ y x \ge y xy 状态的概率为 c u r cur cur,那么 A l i c e Alice Alice 会存在 c u r ∗ q 0 ∗ ( 1 − q 1 ⌊ x y ⌋ 1 − q 1 ) cur*q_0*(\frac{1-q_1^{\lfloor \frac{x}{y}\rfloor}}{1-q_1}) curq0(1q11q1yx) 的概率获胜,把该概率加到 a n s ans ans之中,然后转移到下一个状态 x < y x<y x<y x x x 变成 x m o d    y x \mod y xmody y y y 不变) ,到达的下一个状态概率为 c u r ∗ q 0 ⌊ x y ⌋ cur*q_0^{\lfloor \frac{x}{y}\rfloor} curq0yx

如果到达 x < y x<y x<y 状态的概率为 c u r cur cur,则转移到下一个状态 x ≥ y x \ge y xy x x x 不变, y y y 变成 y m o d    x y \mod x ymodx),对应的到达概率为 c u r ∗ p 0 ⌊ y x ⌋ cur*p_0^{\lfloor \frac{y}{x}\rfloor} curp0xy

可以发现,状态转换的方式是和辗转相除法一样的,这个计算过程的复杂度为 O ( log ⁡ m a x ( x , y ) ) O(\log max(x,y)) O(logmax(x,y)),因为需要用快速幂求逆元和次幂,所以总的复杂度为 O ( log ⁡ 2 m a x ( x , y ) ) O(\log^2 max(x,y)) O(log2max(x,y))

复杂度

时间复杂度 O ( log ⁡ 2 m a x ( x , y ) ) O(\log^2 max(x,y)) O(log2max(x,y)),空间复杂度 O ( 1 ) O(1) O(1)

代码实现

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

#define int long long

const int mod = 998244353;

int x, y, a0, a1, b, p0, p1, ans;

int qmi(int a, int b)
{
    int res = 1;
    a %= mod;
    while (b) {
        if (b & 1)
            res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

int inv(int x)
{
    return qmi(x % mod, mod - 2);
}

void dfs(int cur, int x, int y)
{
    // cout << x << ' ' << y << '\n';
    if (!x)
        return;
    if (!y) {
        ans = (ans + cur) % mod;
        return;
    }
    if (x < y) {
        dfs(cur * qmi(p0, y / x) % mod, x, y % x);
    } else {
        int k = x / y;
        int mul = (1 - qmi(p1, k) + mod) % mod * inv(1 - p1 + mod) % mod * p0 % mod;
        // cout << mul << '\n';
        ans = (ans + cur * mul % mod) % mod;
        dfs(cur * qmi(p1, k) % mod, x % y, y);
    }
}

void solve()
{
    cin >> x >> y >> a0 >> a1 >> b;
    p0 = a0 * inv(a0 + a1) % mod;
    p1 = a1 * inv(a0 + a1) % mod;
    // cout << p0 << ' ' << p1 << '\n';
    ans = 0;
    dfs(1, x, y);
    cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    // cout << inv(2) << '\n';
}

J. Stacking of Goods

题意

n n n 个货物,每个货物有三个属性 w , v , c w,v,c w,v,c

可以将货物从左到右任意排列,排列之后,若第 i i i 个货物左边所有货物的 w w w 之和为 W W W,则该货物的价值为 v i − c i ∗ W v_i - c_i *W viciW

问所有货物价值的总和的最小值可能是多少?

数据范围

1 ≤ n , w i ≤ 1 0 5 , 1 ≤ v i ≤ 1 0 12 , 0 ≤ c i ≤ v i ∑ w i 1 \le n,w_i \le 10^5,1\le v_i \le 10^{12},0 \le c_i \le \frac{v_i}{\sum w_i} 1n,wi105,1vi1012,0ciwivi

思路

如果已经安排好了 m m m 个货物,可以发现交换第 m − 1 m-1 m1 个货物和第 m − 2 m-2 m2 个货物,只会影响到第 m − 1 , m − 2 m-1,m-2 m1,m2 个货物的价值。

若前 m − 3 m-3 m3 个货物的 w w w 之和为 S S S,价值总和为 V V V,那么未交换之前,前 m m m 个货物的价值总和为 V + ( v m − 2 − c m − 2 ∗ S ) + ( v m − 1 − c m − 1 ∗ ( S + w m − 2 ) ) V + (v_{m-2} - c_{m-2}*S) + (v_{m-1} - c_{m-1}*(S+w_{m-2})) V+(vm2cm2S)+(vm1cm1(S+wm2)),交换之后前 m m m 个货物的价值总和为 V + ( v m − 1 − c m − 1 ∗ S ) + ( v m − 2 − c m − 2 ∗ ( S + w m − 1 ) ) V + (v_{m-1} - c_{m-1}*S) + (v_{m-2} - c_{m-2}*(S+w_{m-1})) V+(vm1cm1S)+(vm2cm2(S+wm1))

如果未交换前的价值总和较大,那么满足 V + ( v m − 2 − c m − 2 ∗ S ) + ( v m − 1 − c m − 1 ∗ ( S + w m − 2 ) ) < V + ( v m − 1 − c m − 1 ∗ S ) + ( v m − 2 − c m − 2 ∗ ( S + w m − 1 ) ) V + (v_{m-2} - c_{m-2}*S) + (v_{m-1} - c_{m-1}*(S+w_{m-2}))<V + (v_{m-1} - c_{m-1}*S) + (v_{m-2} - c_{m-2}*(S+w_{m-1})) V+(vm2cm2S)+(vm1cm1(S+wm2))<V+(vm1cm1S)+(vm2cm2(S+wm1)),化简之后可以得到 c m − 2 ∗ w m − 1 < c m − 1 ∗ w m − 2 c_{m-2}*w_{m-1}<c_{m-1}*w_{m-2} cm2wm1<cm1wm2 c m − 2 w m − 2 < c m − 1 w m − 1 \frac{c_{m-2}}{w_{m-2}} < \frac{c_{m-1}}{w_{m-1}} wm2cm2<wm1cm1)。

通过上式,可以发现把 c w \frac{c}{w} wc 较小的尽可能放在前面可以使得价值之和最小化,所以把货物按 c w \frac{c}{w} wc 从小到大排序,然后计算对应的价值总和即为答案。

复杂度

时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn),主要是排序的复杂度,空间复杂度 O ( n ) O(n) O(n)

代码实现

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

#define int long long

const int N = 1e5 + 5;

int n;

struct node {
    int w, v, c;
} a[N];

int cmp(node& p1, node& p2)
{
    return p1.c * p2.w < p2.c * p1.w;
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].w >> a[i].v >> a[i].c;
    }
    sort(a + 1, a + 1 + n, cmp);

    int ans = 0, W = 0;
    for (int i = 1; i <= n; i++) {
        ans += a[i].v - a[i].c * W;
        W += a[i].w;
    }
    cout << ans;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

L. 502 Bad Gateway

题意

起始时,等概率的在 [ 1 , T ] [1,T] [1,T] 中选择一个整数 t 0 t_0 t0,设置初始时间为 t 0 t_0 t0 秒。

在每秒末尾,时间会减少一秒,同时罚时加一,如果减少到 0 0 0 秒则结束。

同时,在每秒末尾可以进行一次操作,等概率的在 [ 1 , T ] [1,T] [1,T] 中选择一个整数 t 1 t_1 t1,重置时间为 t 1 t_1 t1

问可能的最小罚时是多少?以最简分数的形式输出。

数据范围

1 ≤ n ≤ 1 0 6 , 1 ≤ T i ≤ 1 0 9 1 \le n \le 10^6,1 \le T_i \le 10^9 1n106,1Ti109

思路

f ( i ) f(i) f(i) 为初始时间为 i i i 秒的最小罚时。

因为初始时间等概率的为 [ 1 , T ] [1,T] [1,T] 中的一个整数,所以可能的最小罚时 1 T ∑ i = 1 T f ( i ) \frac{1}{T} \sum_{i=1}^T f(i) T1i=1Tf(i)

因为在每秒末尾要么不操作,要么重置时间。

如果不操作,相当于罚时加一,然后初始时间变为 i − 1 i-1 i1,对应的最小罚时为 f ( i − 1 ) + 1 f(i-1)+1 f(i1)+1

如果重置时间,初始时间会等概率的变成 [ 1 , T ] [1,T] [1,T] 中的一个整点 j j j,那么对应的最小罚时为 1 + 1 T ∑ j = 1 T f ( j ) 1 +\frac{1}{T} \sum_{j=1}^T f(j) 1+T1j=1Tf(j)

可以得到 f ( i ) f(i) f(i) 的递推公式, f ( i ) = m i n ( f ( i − 1 ) , 1 T ∑ j = 1 T f ( j ) ) + 1 f(i) = min(f(i-1),\frac{1}{T} \sum_{j=1}^T f(j))+1 f(i)=min(f(i1),T1j=1Tf(j))+1

显然, f ( i ) f(i) f(i) 是随着 i i i 递增而递增的,具有单调性,若 f ( x ) ≤ 1 T ∑ j = 1 T f ( j ) f(x) \le \frac{1}{T} \sum_{j=1}^T f(j) f(x)T1j=1Tf(j),那么 f ( x − 1 ) f(x-1) f(x1) 也满足 f ( x − 1 ) ≤ 1 T ∑ j = 1 T f ( j ) f(x-1) \le \frac{1}{T} \sum_{j=1}^T f(j) f(x1)T1j=1Tf(j)

因此,会存在一个初始时间 x x x,满足 f ( x ) ≤ 1 T ∑ j = 1 T f ( j ) f(x) \le \frac{1}{T} \sum_{j=1}^T f(j) f(x)T1j=1Tf(j) f ( x + 1 ) > 1 T ∑ j = 1 T f ( j ) f(x+1) >\frac{1}{T} \sum_{j=1}^T f(j) f(x+1)>T1j=1Tf(j)

1,初始时间 t 0 ≤ x t_0 \le x t0x,因为对应的最小罚时 f ( t 0 ) ≤ 1 T ∑ j = 1 T f ( j ) f(t_0) \le \frac{1}{T} \sum_{j=1}^T f(j) f(t0)T1j=1Tf(j),所以要使得罚时最小化,最优操作就是不重置时间,对应的最小罚时为 t 0 t_0 t0

2,初始时间 t 0 > x t_0 > x t0>x f ( t 0 ) > 1 T ∑ j = 1 T f ( j ) f(t_0)>\frac{1}{T} \sum_{j=1}^T f(j) f(t0)>T1j=1Tf(j),要使得罚时最小化,需要不断重置时间,直到重置到不超过 x x x 的时间点为止。

若重置到不超过 x x x 的时间点,会有 1 x \frac{1}{x} x1 的概率重置到 [ 1 , x ] [1,x] [1,x] 的任意一个时间点,这部分的最小罚时为 1 x ( 1 + 2 + . . . + x ) = 1 x x ( 1 + x ) 2 = 1 + x 2 \frac{1}{x} (1+2+...+x) = \frac{1}{x}\frac{x(1+x)}{2} = \frac{1+x}{2} x1(1+2+...+x)=x12x(1+x)=21+x

p = x t p = \frac{x}{t} p=tx,表示重置到不超过 x x x 的时间点的概率。

若第 i i i 次重置才重置到 [ 1 , x ] [1,x] [1,x] 内的任意一个时间点,说明前 i − 1 i-1 i1 次都是重置到 [ x + 1 , n ] [x+1,n] [x+1,n] 内,第 i i i 次重置到 [ 1 , x ] [1,x] [1,x] 内,对应的概率为 p ( 1 − p ) i − 1 p(1-p)^{i-1} p(1p)i1,相应的最小罚时相当于重置到 [ 1 , x ] [1,x] [1,x] 的最小罚时 1 + x 2 \frac{1+x}{2} 21+x 加上重置了 i i i 次的罚时 i i i,然后乘上对应的概率,即 ( 1 + x 2 + i ) ∗ p ( 1 − p ) i − 1 (\frac{1+x}{2} +i)*p(1-p)^{i-1} (21+x+i)p(1p)i1

因为这个重置次数是不确定的,可能 1 1 1 次,也可能 2 2 2 次,也可能 3 3 3 次,每种重置次数都存在着对应的概率,因此,所有可能的重置次数对应的最小罚时之和为初始时间 t 0 > x t_0 > x t0>x 对应的最小罚时,可以表示为 ∑ i = 1 + ∞ ( 1 + x 2 + i ) ∗ p ( 1 − p ) i − 1 = 1 + x 2 + p ∑ i = 1 + ∞ i ( 1 − p ) i − 1 \sum_{i=1}^{+\infty} (\frac{1+x}{2} +i)*p(1-p)^{i-1} = \frac{1+x}{2} +p\sum_{i=1}^{+\infty} i(1-p)^{i-1} i=1+(21+x+i)p(1p)i1=21+x+pi=1+i(1p)i1

回忆一下,等比级数可以表示为如下形式:
∑ i = 1 + ∞ x i = lim ⁡ n → + ∞ ∑ i = 1 n x i = lim ⁡ n → + ∞ x ( 1 − x n ) 1 − x = lim ⁡ n → + ∞ 1 − x n + 1 1 − x \sum_{i=1}^{+\infty}x^i = \lim_{n \to +\infty} \sum_{i=1}^{n}x^i = \lim_{n \to +\infty}\frac{x(1-x^n)}{1-x} = \lim_{n \to +\infty}\frac{1-x^{n+1}}{1-x} i=1+xi=n+limi=1nxi=n+lim1xx(1xn)=n+lim1x1xn+1

如果 0 < x < 1 0 < x < 1 0<x<1,那么 lim ⁡ n → + ∞ x n + 1 = 0 \lim_{n \to + \infty} x^{n+1}= 0 limn+xn+1=0,等比级数 ∑ i = 1 + ∞ x i = 1 1 − x \sum_{i=1}^{+\infty}x^i =\frac{1}{1-x} i=1+xi=1x1

注意到,等比级数的导数可以表示为 ∑ i = 1 + ∞ i ∗ x i − 1 = 1 ( 1 − x ) 2 \sum_{i=1}^{+\infty}i*x^{i-1} = \frac{1}{(1-x)^2} i=1+ixi1=(1x)21(对等比级数的式子两边求导),恰好和上面最小罚时中 ∑ i = 1 + ∞ i ( 1 − p ) i − 1 \sum_{i=1}^{+\infty} i(1-p)^{i-1} i=1+i(1p)i1 是一样的。

综上,初始罚时 t 0 > x t_0 >x t0>x,对应的最小罚时为 1 + x 2 + p ∗ 1 ( 1 − ( 1 − p ) ) 2 = 1 + x 2 + 1 p \frac{1+x}{2} + p*\frac{1}{(1-(1-p))^2}=\frac{1+x}{2} + \frac{1}{p} 21+x+p(1(1p))21=21+x+p1

初始时间 t 0 t_0 t0 p p p 的概率为 [ 1 , x ] [1,x] [1,x] 的时间点,这段区间的最小罚时为 p ∗ 1 x ( 1 + 2 + . . . + x ) = p ∗ 1 + x 2 p*\frac{1}{x}(1+2+...+x)=p*\frac{1+x}{2} px1(1+2+...+x)=p21+x,有 1 − p 1-p 1p 的概率为 [ x + 1 , T ] [x+1,T] [x+1,T] 的时间点,这段时间的最小罚时为 ( 1 − p ) ∗ ( 1 + x 2 + 1 p ) (1-p)*(\frac{1+x}{2}+\frac{1}{p}) (1p)(21+x+p1),这两部分加起来为 1 + x 2 + 1 p − 1 = 1 + x 2 + T x − 1 \frac{1+x}{2} + \frac{1}{p}-1 = \frac{1+x}{2} + \frac{T}{x}-1 21+x+p11=21+x+xT1,这个便是答案的随 x x x 变化的函数。

1 + x 2 + T x − 1 \frac{1+x}{2} + \frac{T}{x}-1 21+x+xT1 进行求导,得到 − T x 2 + 1 2 -\frac{T}{x^2} + \frac{1}{2} x2T+21,令 − T x 2 + 1 2 = 0 -\frac{T}{x^2} + \frac{1}{2} = 0 x2T+21=0,得到 x = 2 T x = \sqrt {2T} x=2T ,在正半轴该导函数是单调递增的,意味着若 x < 2 T x< \sqrt{2T} x<2T ,因为导函数小于 0 0 0 1 + x 2 + T x − 1 \frac{1+x}{2} + \frac{T}{x}-1 21+x+xT1 呈递减趋势,否则呈递增趋势,所以 1 + x 2 + T x − 1 \frac{1+x}{2} + \frac{T}{x}-1 21+x+xT1 2 T \sqrt{2T} 2T 处取得极小值。(因为最后取得是整点,所以答案的极值点是在 2 T \sqrt{2T} 2T 上下取整中的一个点)

因为代码实现的时候需要以分数形式输出,分数运算中涉及最小公倍数和最大公因子,需要用到辗转相除法,复杂度是 O ( log ⁡ T ) O(\log T) O(logT) 的。

复杂度

时间复杂度为 O ( log ⁡ T ) O(\log T) O(logT) ,空间复杂度为 O ( 1 ) O(1) O(1)

代码实现

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

#define int long long

struct val {
    int x, y;
    val(int _x, int _y)
    {
        int _g = __gcd(_x, _y);
        x = _x / _g, y = _y / _g;
    }
    val operator+(const val& it) const&
    {
        int ny = y / __gcd(y, it.y) * it.y;
        int nx = ny / y * x + ny / it.y * it.x;
        return val(nx, ny);
    }
    bool operator<(const val& it) const&
    {
        return x * it.y < it.x * y;
    }
};

void solve()
{
    int n;
    cin >> n;
    val ans(2e9, 1);
    int v = sqrt(2 * n);
    // v 为下取整的极值点,v+1 为上取整
    for (int i = 0; i <= 1; i++) {
        if (v + i > 0) {
            // 	(x+1)/2 + n/x - 1
            int x = v + i;
            val t = val(x + 1, 2) + val(n, x) + val(-1, 1);
            if (t < ans)
                ans = t;
        }
    }
    cout << ans.x << ' ' << ans.y << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

http://www.kler.cn/a/323011.html

相关文章:

  • cmake生成器表达式
  • 15分钟学 Go 第 56 天:架构设计基本原则
  • 【Linux】介绍和基础01
  • 坚果云·无法连接服务器(无法同步)
  • [JAVA]有关MyBatis环境配置介绍
  • 电子应用产品设计方案-9:全自动智能马桶系统设计方案
  • vue-cli,element-plus,axios,proxy
  • 31 变量的访问方式(直接和间接),内存地址(32 位和 64 位),指针的概念与定义,取址与取值运算符( 与 *)
  • Spark Streaming 容错机制详解
  • 【Docker】如何让docker容器正常使用nvidia显卡
  • 处理execl表格的库----openpyxl
  • C++ 文件I/O流
  • 【SpringBoot详细教程】-03-整合Junit【持续更新】
  • 代码随想录Day 57|prim算法和kruskal算法精讲,题目:寻宝
  • 提升效率的秘密武器选择指南
  • PTH原理 补丁+工具
  • Java项目——苍穹外卖总结
  • Linux usb hub阅读
  • 【学习】电脑上有多个GPU,命令行指定GPU进行训练。
  • C语言习题~day33
  • 【Unity保龄球项目】的实现逻辑以及代码解释
  • Python Daphne库:ASGI服务的高效Web服务器
  • 使用FFmpeg压缩MP3格式音频
  • 利用模糊综合评价法进行数值评分计算——代码实现
  • 基于Java开发的(控制台)模拟的多用户多级目录的文件系统
  • Redis的主要特点及运用场景