「FJWC2020Day5-zzq」rng 题解

news/2024/11/19 14:39:42/文章来源:https://www.cnblogs.com/XuYueming/p/18432780

题意简述

一个长度为 \(n\) 的实数序列 \(a_i\),其中 \(a_i\)\([l_i, r_i]\) 中独立均匀随机选取的实数。你只能通过交换相邻两个数,使得 \(a_i\) 单调不降。你需要求出你最少操作次数的期望,对 \(M = 998244353\) 取模。

\(1 \leq n \leq 10^6\)\(0 \leq l_i \lt r_i \leq 10^{18}\)

题目分析

由于 \(l_i \lt r_i\),所以两个数 \(a_i = a_j\) 的概率为 \(0\),对答案没有贡献。我们的问题就是 \(a_i\) 的逆序对个数的期望了。

由数学期望的性质,我们考虑每一对 \(i < j\) 对答案的贡献,是这对 \((i, j)\) 为逆序对的概率,乘上 \(1\)。那么累加后,答案即为 \(\sum \operatorname{P}(a_i > a_j)\)

我们先来考虑 \(\Theta(n^2)\) 的算法,问题变成了如何求 \(p \in [l_1, r_i] > q \in [l_2, r_2]\) 的概率。一个想法是对这两段区间的关系进行分讨。

分 $6$ 种情况讨论

其实并不复杂?因为 \((1, 6), (2, 5), (3, 4)\) 是左右对称的,我们解决一半,另一半倒着做一遍,再取概率另一半即可。我们不妨考虑 \((1, 4, 5)\)

\(1\) 很容易计算,使用树状数组扫一下就行了。

关于 \(4\),我们考虑两种情况,第一种是 \(a_i\) 取到了 \(r_j \sim r_i\),此时无论 \(a_j\) 的取值,总有 \(a_i \gt a_j\);第二种是 \(a_i\)\(a_j\) 同时取到了 \(l_j \sim r_j\),此时问题为两个随机变量 \(\lambda, \varphi\) 取值范围相同,求 \(\lambda \gt \varphi\) 的概率,结论是 \(\dfrac{1}{2}\)

点击展开进一步说明

不妨假设取值范围为 \([l, r]\),不失一般性,不妨整体下移 \(l\),即考虑 \([0, r - l]\),记 \(p = r - l\)

对于一个确定的 \(\lambda\),随机出 \(\varphi \lt \lambda\) 的概率为 \(\operatorname{P}(\varphi \lt \lambda \mid \lambda) = \dfrac{\lambda}{p}\)

\[\begin{aligned} \operatorname{P}(\lambda \gt \varphi) &= \int _ {0} ^ p \dfrac{1}{p} \dfrac{\lambda}{p} \mathrm{d} \lambda \\&= \dfrac{1}{p^2} \int _ {0} ^ p \lambda \mathrm{d} \lambda \\&= \dfrac{1}{p^2} \dfrac{p^2}{2} \\&= \dfrac{1}{2} \end{aligned} \]

如果你不太理解,请阅读后文图形化的说明。

此时,列式表达即为 \({\displaystyle \frac{1}{2}\frac{\operatorname{len}_j}{\operatorname{len}_i}+\frac{r_i - r_j}{\operatorname{len}_i} = \frac{1}{2\operatorname{len}_i}\operatorname{len}_j+\frac{1}{\operatorname{len}_i}\left(r_i - r_j\right)}\)

关于 \(5\),只用当 \(a_i, a_j\) 都取到 \(l_j \sim r_i\) 时,才有可能成为逆序对,概率为 \({\displaystyle \frac{r_i - l_j}{\operatorname{len}_i} \frac{r_i - l_j}{\operatorname{len}_j} \frac{1}{2}}\)。我们来一步步化简:

\[\begin{aligned} &\quad \ \frac{r_i - l_j}{\operatorname{len}_i} \frac{r_i - l_j}{\operatorname{len}_j} \frac{1}{2} \\ &= \frac{1}{2\operatorname{len}_i} \frac{r_i^2 -l_j^2 - 2r_il_j}{\operatorname{len}_j} \\ &= \frac{1}{2\operatorname{len}_i}\left(\frac{r_i^2}{\operatorname{len}_j}-\frac{l_j^2}{\operatorname{len}_j}-\frac{2r_il_j}{\operatorname{len}_j}\right) \\ &= \frac{1}{2\operatorname{len}_i}\left(r_i^2\frac{1}{\operatorname{len}_j}-\frac{l_j^2}{\operatorname{len}_j}-2r_i\frac{l_j}{\operatorname{len}_j}\right) \end{aligned} \]

对于每一种情况,我们都将其拆成了多个关于 \(i\) 和关于 \(j\) 的项乘积的形式,形如 \(v_i c_j\)。我们从右向左扫,用一个数据结构维护 \(\sum c_j\),查询满足特定条件的 \(\sum c_j\),贡献为 \(\sum v_i c_j = v_i \sum c_j\)

这样的 \(c_j\)\(6\) 种,分别为:

  1. \(1\)
  2. \(\operatorname{len}_j\)
  3. \(r_j\)
  4. \(\dfrac{1}{\operatorname{len}_j}\)
  5. \(\dfrac{l_j^2}{\operatorname{len}_j}\)
  6. \(\dfrac{l_j}{\operatorname{len}_j}\)

怎么样,是心动的感觉~

问题就出在了「特定条件」,无论是 \(4\) 还是 \(5\),我们对 \(j\)\(l_j, r_j\) 都有限定。这样的三维偏序问题,就不得不 CDQ 或树套树了,但无论如何,\(\Theta(n \log ^ 2 n)\) 的时间是我们无法接受的。

点击展开题外话

其实原题 \(n \leq 10^5\),也不是没有可能,如果你帮我把文末 \(25.7\)KiB、\(736\) 行的性感代码卡过了,请收下我一拜!

似乎不好整,换个方法吧。我们想办法越过对于 \(a_i, a_j\) 的取值区间的关系的分析,这也是我们上述算法瓶颈之根本所在。发现是连续变量的二元关系,和概率有关,应该需要放到平面直角坐标系上观察,且和面积要搭上边。

我们把横轴设为 \(a_i\),纵轴设为 \(a_j\),那么合法的 \((a_i, a_j)\) 构成了平面上一个矩形。直线 \(a_i = a_j\) 下方的部分就表示 \(a_i \gt a_j\)

动手试试吧!

紫色部分的面积比上总面积,就是 \(a_i > a_j\) 的概率,问题变成求这个不规则的图形的面积。如果分类讨论又要回到上面了,那我们换一种思路,用容斥,也就是小奥中一种方法,用规则图形拼出不规则图形。我们这里规则图形是什么?很显然,和 \(y = x\) 和横轴构成的三角形有关。用若干这样的三角形就能拼凑出紫色部分。这很类似二位前缀和,我们记 \(g(\lambda, \varphi)\) 表示,\(x \in [0, \lambda], y \in [0, \varphi]\) 的矩形内,\(x \gt y\) 部分的面积。那么 \(a_i \gt a_j\) 的概率即为:

\[\frac{g(r_i, r_j) - g(r_i, l_j) - g(l_i, r_j) + g(l_i, l_j)}{\operatorname{len}_i \operatorname{len}_j} \]

接下来研究 \(g(\lambda, \varphi)\),尝试得到一个简单的表达式。

动手试试吧!

此时好像要分 \(\lambda \leq \varphi\)\(\lambda \gt \varphi\) 两种情况讨论了,但比上面 \(6\) 类简单多了,不是吗?

分类讨论:$\lambda \leq \varphi$(左);$\lambda \gt \varphi$(右)

得到:

\[g(\lambda, \varphi) = \left\{\begin{matrix} \dfrac{\lambda^2}{2} & \text{if} \ \lambda \leq \varphi\\ \varphi \lambda - \dfrac{\varphi^2}{2} & \text{if} \ \lambda \gt \varphi\\ \end{matrix}\right. \]

关于上文「进一步说明」

注意到,当 \(\lambda = \varphi\) 的时候,满足条件部分恰好是整个正方形的 \(\dfrac{1}{2}\),也就是我们的结论。

看看我们要算的:

\[\frac{\Big(\frac{g(r_i, r_j)}{\operatorname{len}_j} - \frac{g(r_i, l_j)}{\operatorname{len}_j}\Big) - \Big(\frac{g(l_i, r_j)}{\operatorname{len}_j} - \frac{g(l_i, l_j)}{\operatorname{len}_j}\Big)}{\operatorname{len}_i} \]

显然从右往左扫,需要用数据结构维护 \(j > i\) 的信息。我们只需要用 \(3\) 个树状数组维护:

  1. \(\dfrac{1}{\operatorname{len}_j}\)
  2. \(\dfrac{\varphi}{\operatorname{len}_j}\)
  3. \(\dfrac{\varphi^2}{\operatorname{len}_j}\)

其中 \(\varphi\) 是关于 \(l_j, r_j\) 的变量。由于我们查询的时候并不关心是 \(l_j\) 还是 \(r_j\),只关心 \(l_j\) 前的系数是 \(-1\),那么我们在插入时,就插入 \(-l_j\) 即可。查询的时候就很方便了,分讨一下,用 \(r_i\) 的答案减去 \(l_i\) 的答案即可。

时间复杂度 \(\Theta(n \log nM)\),空间复杂度 \(\Theta(n)\)

代码

根据原题 \(0 \leq l_i \lt r_i \leq 10^8\)

$25.7$KiB、$736$ 行的性感代码
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <ctime>
using namespace std;char ST;const int MAX = 1 << 26;
char buf[MAX], *p = buf;
#ifdef XuYueming
# define fread(_, __, ___, ____)
#else
# define getchar() *p++
#endif
#define isdigit(x) ('0' <= x && x <= '9')
#define __yzh__(x) for (; x isdigit(ch); ch = getchar())
template <typename T>
inline void read(T &x) {x = 0; char ch = getchar(); __yzh__(!);__yzh__( ) x = (x << 3) + (x << 1) + (ch ^ 48);
}constexpr int N = 100010;
constexpr int mod = 998244353;
constexpr int inv2 = (mod + 1) >> 1;
using lint = long long;
using ull = unsigned lint;constexpr __int128_t _base = ((__int128_t)(1) << 64) / mod;
inline long long mol(long long x){return x - mod * (_base * x >> 64);
}inline int add(int a, int b) {return a + b >= mod ? a + b - mod : a + b;
}
inline int sub(int a, int b) {return a - b < 0 ? a - b + mod : a - b;
}
inline int mul(int a, int b) {return mol(1ll * a * b);
}
inline int pow(int a, int b) {int res = 1;for (; b; b >>= 1, a = mul(a, a))if (b & 1) res = mul(res, a);return res;
}
inline int inv(int x) {return pow(x, mod - 2);
}int n;
int L[N], R[N];namespace pts60 {inline bool check() {return n <= 5000;}inline int in(int a, int b) {// a 里挑 breturn mul(b, inv(a));}int big(int l1, int r1, int l2, int r2) {// [l1, r1] > [l2, r2]if (l1 > l2) return sub(1, big(l2, r2, l1, r1));if (l2 >= r1) return 0;if (r2 <= r1) {int res = 0;res = add(res, in(r1 - l1, r1 - r2));res = add(res, mul(inv2, in(r1 - l1, r2 - l2)));return res;} else {return mul(inv2, mul(in(r1 - l1, r1 - l2), in(r2 - l2, r1 - l2)));}}void solve() {int ans = 0;for (int i = 1; i <= n; ++i)for (int j = i + 1; j <= n; ++j) {ans = add(ans, big(L[i], R[i], L[j], R[j]));}printf("%d", ans);}
}namespace l0 {inline bool check() {for (int i = 1; i <= n; ++i)if (L[i] != 0) return false;return true;}int real[N], V;struct Bit_Tree {static inline int lowbit(int x) {return x & -x;}int tree[N];inline void modify(int p, int v) {for (int i = p; i <= V; i += lowbit(i))tree[i] = add(tree[i], v);}inline int query(int p) {int res = 0;for (int i = p; i; i -= lowbit(i))res = add(res, tree[i]);return res;}} yzh, cnter;void solve() {for (int i = 1; i <= n; ++i)real[++V] = R[i];sort(real + 1, real + V + 1);V = unique(real + 1, real + V + 1) - real - 1;int ans = 0;for (int i = n; i >= 1; --i) {int r = lower_bound(real + 1, real + V + 1, R[i]) - real;ans = add(ans, cnter.query(r));ans = sub(ans, mul(mul(inv2, inv(R[i])), yzh.query(r)));yzh.modify(r, R[i]);cnter.modify(r, 1);}memset(yzh.tree, 0x00, sizeof (yzh.tree));for (int i = 1; i <= n; ++i) {int r = lower_bound(real + 1, real + V + 1, R[i]) - real;ans = add(ans, mul(mul(inv2, inv(R[i])), yzh.query(r - 1)));yzh.modify(r, R[i]);}printf("%d", ans);}
}namespace yzh520 {#define fint unsigned// using fint = unsigned;  // maybe unsigned is faster than signedconstexpr fint mod = 998244353;constexpr fint inv2 = (mod + 1) >> 1;constexpr __int128_t _base = ((__int128_t)(1) << 64) / (signed)mod;inline long long mol(long long x){// return x % mod;return x - 1ll * (signed)mod * (_base * x >> 64);}inline fint add(fint a, fint b) {return a + b >= mod ? a + b - mod : a + b;}// #undef fint// #define fint intinline fint sub(fint a, fint b) {// if (a >= mod) cerr << "A " << a << endl, printf("%p,%p\n", __builtin_return_address(0), __builtin_return_address(1)), throw -1;// if (b >= mod) cerr << "B " << b << endl, printf("%p,%p\n", __builtin_return_address(0), __builtin_return_address(1)), throw -1;// a %= mod, b %= mod;return a < b ? a + mod - b : a - b;}// #undef fint// #define fint unsignedinline fint mul(fint a, fint b) {return 1llu * a * b % mod;// return mol(1ll * (signed)a * (signed)b);}inline fint pow(fint a, fint b) {fint res = 1;for (; b; b >>= 1, a = mul(a, a))if (b & 1) res = mul(res, a);return res;}inline fint inv(fint x) {return pow(x, mod - 2);}fint ll[N], rr[N], invlen[N];fint real[N << 1], V;struct Bit_Tree {static constexpr inline fint lowbit(fint x) {return x & -x;}fint tree[N << 1];inline void modify(fint p, fint v) {for (register fint i = p; i <= V; i += lowbit(i))tree[i] = add(tree[i], v);}inline fint query(fint p) {fint res = 0;for (register fint i = p; i; i -= lowbit(i))res = add(res, tree[i]);return res;}// inline void clear() {//     memset(tree, 0x00, sizeof (int) * (V + 10));// }} cnter;namespace New_Segment_Tree {// struct New_Segment_Tree {struct node {fint lson, rson, sum[6];} tree[N * 520];fint tot, sum[6], p, l, r;void modify(fint &idx, fint trl, fint trr) {if (!idx) tree[idx = ++tot] = {};tree[idx].sum[0] = add(tree[idx].sum[0], sum[0]);tree[idx].sum[1] = add(tree[idx].sum[1], sum[1]);tree[idx].sum[2] = add(tree[idx].sum[2], sum[2]);tree[idx].sum[3] = add(tree[idx].sum[3], sum[3]);tree[idx].sum[4] = add(tree[idx].sum[4], sum[4]);tree[idx].sum[5] = add(tree[idx].sum[5], sum[5]);if (trl == trr) return;fint mid = (trl + trr) >> 1;if (p <= mid) modify(tree[idx].lson, trl, mid);else modify(tree[idx].rson, mid + 1, trr);}void query_add(fint idx, fint trl, fint trr) {if (l <= trl && trr <= r) {sum[0] = add(sum[0], tree[idx].sum[0]);sum[1] = add(sum[1], tree[idx].sum[1]);sum[2] = add(sum[2], tree[idx].sum[2]);sum[3] = add(sum[3], tree[idx].sum[3]);sum[4] = add(sum[4], tree[idx].sum[4]);sum[5] = add(sum[5], tree[idx].sum[5]);return;}fint mid = (trl + trr) >> 1;if (l <= mid && tree[idx].lson) query_add(tree[idx].lson, trl, mid);if (r  > mid && tree[idx].rson) query_add(tree[idx].rson, mid + 1, trr);}void query_sub(fint idx, fint trl, fint trr) {if (l <= trl && trr <= r) {sum[0] = sub(sum[0], tree[idx].sum[0]);sum[1] = sub(sum[1], tree[idx].sum[1]);sum[2] = sub(sum[2], tree[idx].sum[2]);sum[3] = sub(sum[3], tree[idx].sum[3]);sum[4] = sub(sum[4], tree[idx].sum[4]);sum[5] = sub(sum[5], tree[idx].sum[5]);return;}fint mid = (trl + trr) >> 1;if (l <= mid && tree[idx].lson) query_sub(tree[idx].lson, trl, mid);if (r  > mid && tree[idx].rson) query_sub(tree[idx].rson, mid + 1, trr);}};namespace Segment_Tree {// struct Segment_Tree {fint tree[N << 1];// unsigned tree[N << 1];// New_Segment_Tree tr;inline void clear() {memset(tree + 1, 0x00, sizeof (fint) * V);New_Segment_Tree::tot = 0;}inline void modify(fint l, fint r, fint L, fint R) {New_Segment_Tree::sum[0] = R - L;New_Segment_Tree::sum[1] = R;New_Segment_Tree::sum[4] = 1;New_Segment_Tree::sum[5] = inv(R - L);New_Segment_Tree::sum[3] = mul(L, New_Segment_Tree::sum[5]);New_Segment_Tree::sum[2] = mul(New_Segment_Tree::sum[3], L);New_Segment_Tree::p = r;for (register fint i = l; i <= V; i += Bit_Tree::lowbit(i))New_Segment_Tree::modify(tree[i], 1, V);}inline void query(fint ll, fint lr, fint rl, fint rr) {New_Segment_Tree::sum[0] = New_Segment_Tree::sum[1] = New_Segment_Tree::sum[2] = New_Segment_Tree::sum[3] = New_Segment_Tree::sum[4] = New_Segment_Tree::sum[5] = 0;if (ll > lr || rl > rr) return;New_Segment_Tree::l = rl, New_Segment_Tree::r = rr, --ll;for (; lr > ll; lr -= Bit_Tree::lowbit(lr)) New_Segment_Tree::query_add(tree[lr], 1, V);for (; ll > lr; ll -= Bit_Tree::lowbit(ll)) New_Segment_Tree::query_sub(tree[ll], 1, V);}// } yzh;}void solve() {for (register fint i = 1; i <= n; ++i) {real[++V] = L[i];real[++V] = R[i];}sort(real + 1, real + V + 1);V = unique(real + 1, real + V + 1) - real - 1;register fint ans = 0;for (register fint i = n; i; --i) {ll[i] = lower_bound(real + 1, real + V + 1, L[i]) - real;rr[i] = lower_bound(real + 1, real + V + 1, R[i]) - real;ans += cnter.query(ll[i]);cnter.modify(rr[i], 1);}fprintf(stderr, "\nTime used %.2lfs. (start)\n", clock() * 1. / CLOCKS_PER_SEC);for (register fint i = n, inv_len_i, TTT, inv2len; i; --i) {inv_len_i = invlen[i] = inv(R[i] - L[i]), inv2len = mul(inv2, inv_len_i);Segment_Tree::query(ll[i], rr[i], ll[i], rr[i]);ans = add(ans, mul(inv_len_i, sub(mul(New_Segment_Tree::sum[4], R[i]), New_Segment_Tree::sum[1])));ans = add(ans, mul(inv2len, New_Segment_Tree::sum[0]));if (rr[i] != V) {Segment_Tree::query(ll[i], rr[i], rr[i] + 1, V);TTT = mul(mul(R[i], R[i]), New_Segment_Tree::sum[5]);TTT = sub(TTT, mul(mul(2u, R[i]), New_Segment_Tree::sum[3]));TTT = add(TTT, New_Segment_Tree::sum[2]);TTT = mul(TTT, inv2len);ans = add(ans, TTT);}Segment_Tree::modify(ll[i], rr[i], L[i], R[i]);}fprintf(stderr, "\nTime used %.2lfs. (half)\n", clock() * 1. / CLOCKS_PER_SEC);Segment_Tree::clear();for (register fint i = 1, inv_len_i, TTT, inv2len; i <= n; ++i) {inv_len_i = invlen[i], inv2len = mul(inv2, inv_len_i);if (ll[i] + 1 < rr[i]) {Segment_Tree::query(ll[i] + 1, rr[i], ll[i] + 1, rr[i]);ans = add(ans, New_Segment_Tree::sum[4]);ans = sub(ans, mul(inv_len_i, sub(mul(New_Segment_Tree::sum[4], R[i]), New_Segment_Tree::sum[1])));ans = sub(ans, mul(inv2len, New_Segment_Tree::sum[0]));}if (rr[i] != V && ll[i] + 2 <= rr[i]) {Segment_Tree::query(ll[i] + 1, rr[i] - 1, rr[i] + 1, V);TTT = mul(mul(2u, R[i]), New_Segment_Tree::sum[3]);TTT = sub(TTT, mul(mul(R[i], R[i]), New_Segment_Tree::sum[5]));TTT = sub(TTT, New_Segment_Tree::sum[2]);TTT = mul(TTT, inv2len);TTT = add(New_Segment_Tree::sum[4], TTT);ans = add(ans, TTT);}Segment_Tree::modify(ll[i], rr[i], L[i], R[i]);}printf("%u", ans);fprintf(stderr, "\nTime used %.2lfs.\n", clock() * 1. / CLOCKS_PER_SEC);}
}#if false && defined xym_loves_yzh
namespace yzh520 {int ll[N], rr[N];int real[N << 1], V;struct Bit_Tree {static inline int lowbit(int x) {return x & -x;}int tree[N << 1];inline void modify(int p, int v) {for (int i = p; i <= V; i += lowbit(i))tree[i] = add(tree[i], v);}inline int query(int p) {int res = 0;for (int i = p; i; i -= lowbit(i))res = add(res, tree[i]);return res;}inline void clear() {memset(tree, 0x00, sizeof (int) * (V + 10));}} cnter;struct New_Segment_Tree {// unordered_map<int, int> tr[N * 20][6];// int sum[6], tot;// void modify(int &idx, [[maybe_unused]] int _, [[maybe_unused]] int __, int p) {//     if (!idx) {//         idx = ++tot;//         for (int j = 0; j < 6; ++j)//             tr[idx][j].clear();//     }//     for (int j = 0; j < 6; ++j) {//         for (int i = p; i <= V; i += Bit_Tree::lowbit(i))//             tr[idx][j][i] += sum[j];//     }// }// void query(int idx, int p, int f) {//     if (!idx) return;//     for (int j = 0; j < 6; ++j) {//         for (int i = p; i; i -= Bit_Tree::lowbit(i))//             if (tr[idx][j].count(i))//                 sum[j] += tr[idx][j][i];//     }// }// void query(int idx, [[maybe_unused]] int _, [[maybe_unused]] int __, int l, int r) {//     query(idx, r, 1);//     query(idx, l - 1, -1);// }struct node {int lson, rson, sum[6];} tree[N * 520];  // more----------------------------------------int tot, sum[6];void modify(int &idx, int trl, int trr, int p) {if (trl > p || trr < p) return;if (!idx) tree[idx = ++tot] = {};for (int i = 0; i < 6; ++i)tree[idx].sum[i] = add(tree[idx].sum[i], sum[i]);if (trl == trr) return;int mid = (trl + trr) >> 1;modify(tree[idx].lson, trl, mid, p);modify(tree[idx].rson, mid + 1, trr, p);}void query(int idx, int trl, int trr, int l, int r) {if (trl > r || trr < l || !idx) return;if (l <= trl && trr <= r) {for (int i = 0; i < 6; ++i)sum[i] = add(sum[i], tree[idx].sum[i]);return;}int mid = (trl + trr) >> 1;query(tree[idx].lson, trl, mid, l, r);query(tree[idx].rson, mid + 1, trr, l, r);}};struct Segment_Tree {#define lson (idx << 1    )#define rson (idx << 1 | 1)int tree[N << 3];New_Segment_Tree tr;void build(int idx, int l, int r) {tree[idx] = 0;if (l == r) return;int mid = (l + r) >> 1;build(lson, l, mid);build(rson, mid + 1, r);}void clear() {tr.tot = 0;build(1, 1, V);}void modify(int idx, int trl, int trr, int l, int r) {if (trl > l || trr < l) return;tr.modify(tree[idx], 1, V, r);if (trl == trr) return;int mid = (trl + trr) >> 1;modify(lson, trl, mid, l, r);modify(rson, mid + 1, trr, l, r);}void modify(int l, int r, int L, int R) {tr.sum[0] = R - L;tr.sum[1] = R;tr.sum[4] = 1;tr.sum[5] = inv(R - L);tr.sum[3] = mul(L, tr.sum[5]);tr.sum[2] = mul(tr.sum[3], L);// cout << "update len " << tr.sum[0] << endl;modify(1, 1, V, l, r);}void query(int idx, int trl, int trr, int ll, int lr, int rl, int rr) {if (trl > lr || trr < ll) return;if (ll <= trl && trr <= lr) return tr.query(tree[idx], 1, V, rl, rr);int mid = (trl + trr) >> 1;query(lson, trl, mid, ll, lr, rl, rr);query(rson, mid + 1, trr, ll, lr, rl, rr);}void query(int ll, int lr, int rl, int rr) {tr.sum[0] = tr.sum[1] = tr.sum[2] = tr.sum[3] = tr.sum[4] = tr.sum[5] = 0;if (ll > lr || rl > rr) {// puts("return in query!!!!!");return;}query(1, 1, V, ll, lr, rl, rr);}#undef lson#undef rson} yzh;void solve() {for (int i = 1; i <= n; ++i) {real[++V] = L[i];real[++V] = R[i];}sort(real + 1, real + V + 1);V = unique(real + 1, real + V + 1) - real - 1;for (int i = 1; i <= n; ++i) {ll[i] = lower_bound(real + 1, real + V + 1, L[i]) - real;rr[i] = lower_bound(real + 1, real + V + 1, R[i]) - real;// cout << ll[i] << ' ' << rr[i] << endl;}int ans = 0;for (int i = n; i >= 1; --i) {ans += cnter.query(ll[i]);cnter.modify(rr[i], 1);}// printf("ans = %d\n", ans);// cnter.clear();for (int i = n; i >= 1; --i) {// cout << "i = " << i << endl;int inv_len_i = inv(R[i] - L[i]);yzh.query(ll[i], rr[i], ll[i], rr[i]);ans = add(ans, mul(inv_len_i, sub(mul(yzh.tr.sum[4], R[i]), yzh.tr.sum[1])));ans = add(ans, mul(mul(inv2, inv_len_i), yzh.tr.sum[0]));// if (i == 1) printf(">>> %d\n", ans);if (rr[i] != V// && i == 1) {yzh.query(ll[i], rr[i], rr[i] + 1, V);// cout << "∑ len = " << yzh.tr.sum[0] << endl;// cout << "∑ R = " << yzh.tr.sum[1] << endl;// cout << "∑ L / len = " << yzh.tr.sum[3] << endl;// cout << "∑ L^2 / len = " << yzh.tr.sum[2] << endl;// cout << "cnt = " << yzh.tr.sum[4] << endl;int TTT = 0;TTT = add(TTT, mul(mul(R[i], R[i]), yzh.tr.sum[5]));TTT = sub(TTT, mul(mul(2, R[i]), yzh.tr.sum[3]));TTT = add(TTT, yzh.tr.sum[2]);TTT = mul(TTT, mul(inv2, inv_len_i));ans = add(ans, TTT);// printf(">>> %d\n", ans);// if (i == 1) {//     printf(">>> %d\n", inv(mul(inv(mul(R[i], R[i])), yzh.tr.sum[0])));//     printf(">>> %d\n", mul(mul(2, R[i]), yzh.tr.sum[3]));//     // printf(">>> %d\n", yzh.tr.sum[3]);//     printf(">>> %d\n", yzh.tr.sum[2]);// }}yzh.modify(ll[i], rr[i], L[i], R[i]);// printf("anssss = %d\n", ans);}// printf("ans = %d\n", ans);// puts("---------------------------------------------");yzh.clear();for (int i = 1; i <= n; ++i) {int inv_len_i = inv(R[i] - L[i]);// if (ll[i] + 1 <= rr[i] - 1) {yzh.query(ll[i] + 1, rr[i], ll[i] + 1, rr[i]);ans = add(ans, yzh.tr.sum[4]);ans = sub(ans, mul(inv_len_i, sub(mul(yzh.tr.sum[4], R[i]), yzh.tr.sum[1])));ans = sub(ans, mul(mul(inv2, inv_len_i), yzh.tr.sum[0]));// }// if (i == 3) {//     for (int j = 0; j < 5; ++j)//         printf("sum[%d] = %d\n", j, yzh.tr.sum[j]);// }if (rr[i] != V && ll[i] + 1 <= rr[i] - 1) {yzh.query(ll[i] + 1, rr[i] - 1, rr[i] + 1, V);int TTT = 0;TTT = sub(TTT, mul(mul(R[i], R[i]), yzh.tr.sum[5]));TTT = add(TTT, mul(mul(2, R[i]), yzh.tr.sum[3]));TTT = sub(TTT, yzh.tr.sum[2]);TTT = mul(TTT, mul(inv2, inv_len_i));TTT = add(yzh.tr.sum[4], TTT);// printf(">>> %d\n", TTT);ans = add(ans, TTT);}yzh.modify(ll[i], rr[i], L[i], R[i]);// printf("%d: ans = %d\n", i, ans);}printf("%d", ans);// yzh.clear();// for (int i = 1; i <= n; ++i) {//     int inv_len_i = inv(R[i] - L[i]);//     yzh.query(ll[i] + 1, rr[i] - 1, ll[i] + 1, rr[i] - 1);//     ans = add(ans, yzh.tr.sum[4]);//     ans = sub(ans, mul(inv_len_i, sub(mul(yzh.tr.sum[4], R[i]), yzh.tr.sum[1])));//     ans = sub(ans, mul(mul(inv2, inv_len_i), yzh.tr.sum[0]));//     // if (i == 3) {//     //     for (int j = 0; j < 5; ++j)//     //         printf("sum[%d] = %d\n", j, yzh.tr.sum[j]);//     // }//     if (rr[i] != V) {//         yzh.query(ll[i] + 1, rr[i] - 1, rr[i] + 1, V);//         int TTT = 0;//         TTT = sub(TTT, inv(mul(inv(mul(R[i], R[i])), yzh.tr.sum[0])));//         TTT = add(TTT, mul(mul(2, R[i]), yzh.tr.sum[3]));//         TTT = sub(TTT, yzh.tr.sum[2]);//         TTT = mul(TTT, mul(inv2, inv_len_i));//         TTT = add(yzh.tr.sum[4], TTT);//         // printf(">>> %d\n", TTT);//         ans = add(ans, TTT);//         // if (i == 2) {//         //     printf(">>> %d\n", yzh.tr.sum[4]);//         //     printf(">>> %d\n", inv(mul(inv(mul(R[i], R[i])), yzh.tr.sum[0])));//         //     printf(">>> %d\n", mul(mul(2, R[i]), yzh.tr.sum[3]));//         //     printf(">>> %d\n", yzh.tr.sum[2]);//         // }//         // ans = add(ans, yzh.tr.sum[4]);//         // ans = sub(ans, inv(mul(inv(mul(R[i], R[i])), yzh.tr.sum[0])));//         // ans = add(ans, mul(mul(2, R[i]), yzh.tr.sum[3]));//         // ans = sub(ans, yzh.tr.sum[2]);//     }//     yzh.modify(ll[i], rr[i], L[i], R[i]);//     // printf("%d: ans = %d\n", i, ans);// }// printf("%d", ans);fprintf(stderr, "Time used %.2lfs.\n", clock() * 1. / CLOCKS_PER_SEC);}
}
#endifchar ED;signed main() {fprintf(stderr, "Memory: %.2lf MB\n", (&ED - &ST) / 1024.0 / 1024.0);#ifndef XuYuemingfreopen("rng.in", "r", stdin);freopen("rng.out", "w", stdout);#endiffread(buf, 1, MAX, stdin);read(n);for (register int i = 1; i <= n; ++i)read(L[i]), read(R[i]);// scanf("%d", &n);// for (int i = 1; i <= n; ++i)//     scanf("%d%d", &L[i], &R[i]);#ifndef XuYueming// if (pts60::check()) return pts60::solve(), 0;if (l0::check()) return l0::solve(), 0;#endifreturn yzh520::solve(), 0;
}/*
3
4 9
2 5
1 4
*//*
2
2 3
3 6
*//*
2
7 8
7 9
*//*
2
4 10
3 6
*//*
2
8 10
2 8
*//*
3
8 10
7 9
0 8
*//*
3
0 5
4 9
0 10
*/
#include <cstdio>
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <cassert>
#include <limits>const int N = 100010;namespace Bit_Tree_Class {template <typename T>static constexpr inline T lowbit(T x) {return x & -x;}template <int f>class Jumper {public:static constexpr inline int nxt(int x) { return x + f * lowbit(x); }static constexpr inline int pre(int x) { return x - f * lowbit(x); }};using prefix = Jumper< 1>;using suffix = Jumper<-1>;template <typename T, typename = void>struct hasNxt : std::false_type {};template <typename T>struct hasNxt<T, std::void_t<decltype(std::declval<T>().nxt)>> : std::true_type {};template <typename T, typename = void>struct hasPre : std::false_type {};template <typename T>struct hasPre<T, std::void_t<decltype(std::declval<T>().pre)>> : std::true_type {};template <typename T>auto gen_empty_v = [] () -> T { return T {}; };template <typename T = int, typename jmp = prefix, auto upd = std::plus<T>{}, auto gen_empty_v_func = gen_empty_v<T>, size_t N = N>class Bit_Tree {static_assert(std::is_convertible_v<decltype(upd), std::function<T(T, T)>>,"update function must work with T and T and returns T.");static_assert(hasNxt<jmp>::value, "jumper must have nxt function.");static_assert(hasPre<jmp>::value, "jumper must have pre function.");static_assert(std::conjunction_v<std::is_convertible<decltype(jmp::nxt), std::function<int(int)>>,std::is_convertible<decltype(jmp::pre), std::function<int(int)>>>,"jump functions must work with int and returns int.");static_assert(std::is_convertible_v<decltype(gen_empty_v_func), std::function<T()>>,"gen empty v func must return an empty value of T.");public:constexpr Bit_Tree() = default;constexpr explicit Bit_Tree(int _n): n(_n) { clear(); }constexpr inline void init(int _n) { n = _n, clear(); }constexpr inline void clear() { std::fill(tree + 1, tree + n + 1, empty_v); }constexpr inline void modify(int p, T v) {for (int i = p; 1 <= i && i <= n; i = jmp::nxt(i))tree[i] = upd(tree[i], v);}constexpr inline T query(int p) const {T res = empty_v;for (int i = p; 1 <= i && i <= n; i = jmp::pre(i))res = upd(res, tree[i]);return res;}protected:int n;T tree[N];static constexpr T empty_v = gen_empty_v_func();};template <typename T = int, typename jmp = prefix, auto upd = std::plus<T>{}, auto del = std::minus<T>{},auto gen_empty_v_func = gen_empty_v<T>, size_t N = N>class RQuery_Bit_Tree: public Bit_Tree<T, jmp, upd, gen_empty_v_func, N> {};template <typename T, auto upd, auto del, auto gen_empty_v_func, size_t N>class RQuery_Bit_Tree<T, prefix, upd, del, gen_empty_v_func, N>:public Bit_Tree<T, prefix, upd, gen_empty_v_func, N> {static_assert(std::is_convertible_v<decltype(del), std::function<T(T, T)>>,"del function must work with T and T and returns T.");public:constexpr inline T query(int l, int r) const {using __base = Bit_Tree<T, prefix, upd, gen_empty_v_func, N>;if (l > r) return __base::empty_v;return del(__base::query(r), __base::query(l - 1));}};template <typename T, auto upd, auto del, auto gen_empty_v_func, size_t N>class RQuery_Bit_Tree<T, suffix, upd, del, gen_empty_v_func, N>:public Bit_Tree<T, suffix, upd, gen_empty_v_func, N> {static_assert(std::is_convertible_v<decltype(del), std::function<T(T, T)>>,"del function must work with T and T and returns T.");public:constexpr inline T query(int l, int r) const {using __base = Bit_Tree<T, suffix, upd, gen_empty_v_func, N>;if (l > r) return __base::empty_v;return del(__base::query(l), __base::query(r + 1));}};
}namespace Mod_Int_Class {template <typename T, typename _Tp>constexpr bool in_range(_Tp val) {return std::numeric_limits<T>::min() <= val && val <= std::numeric_limits<T>::max();}template <auto mod = 998244353, typename T = int, typename S = long long>class Mod_Int {static_assert(in_range<T>(mod), "mod must in the range of type T.");static_assert(std::is_integral<T>::value, "type T must be an integer.");static_assert(std::is_integral<S>::value, "type S must be an integer.");public:constexpr Mod_Int() noexcept = default;template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>>constexpr Mod_Int(_Tp v) noexcept: val(0) {if (0 <= v && v < mod) val = v;else val = (v % mod + mod) % mod;}constexpr T const& raw() const {return this -> val;}static constexpr inline T add(T a, T b) {return a + b >= mod ? a + b - mod : a + b;}static constexpr inline T sub(T a, T b) {return a < b ? a - b + mod : a - b;}static constexpr inline T mul(T a, T b) {return static_cast<S>(a) * b % mod;}static constexpr inline T& toadd(T& a, T b) {return a = add(a, b);}static constexpr inline T& tosub(T& a, T b) {return a = sub(a, b);}static constexpr inline T& tomul(T& a, T b) {return a = mul(a, b);}template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>>static constexpr inline T pow(T a, _Tp p) {T res = 1;for (; p; p >>= 1, tomul(a, a))if (p & 1) tomul(res, a);return res;}template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>>static constexpr inline bool is_prime(_Tp val) {if (val < 2) return false;for (_Tp i = 2; i * i <= val; ++i)if (val % i == 0)return false;return true;}template <typename = std::enable_if_t<is_prime(mod)>>static constexpr inline T inv(T a) {assert(a != 0);return pow(a, mod - 2);}constexpr Mod_Int& operator + () const {return *this;}constexpr Mod_Int operator - () const {return sub(0, val);}constexpr friend inline Mod_Int operator + (Mod_Int a, Mod_Int b) {return add(a.val, b.val);}constexpr friend inline Mod_Int operator - (Mod_Int a, Mod_Int b) {return sub(a.val, b.val);}constexpr friend inline Mod_Int operator * (Mod_Int a, Mod_Int b) {return mul(a.val, b.val);}constexpr friend inline Mod_Int operator / (Mod_Int a, Mod_Int b) {return mul(a.val, inv(b.val));}template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>>constexpr friend inline Mod_Int operator ^ (Mod_Int a, _Tp p) {return pow(a, p);}constexpr friend inline Mod_Int& operator += (Mod_Int& a, Mod_Int b) {return a = add(a.val, b.val);}constexpr friend inline Mod_Int& operator -= (Mod_Int& a, Mod_Int b) {return a = sub(a.val, b.val);}constexpr friend inline Mod_Int& operator *= (Mod_Int& a, Mod_Int b) {return a = mul(a.val, b.val);}constexpr friend inline Mod_Int& operator /= (Mod_Int& a, Mod_Int b) {return a = mul(a.val, inv(b.val));}template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value>>constexpr friend inline Mod_Int& operator ^= (Mod_Int& a, _Tp p) {return a = pow(a.val, p);}constexpr friend inline bool operator == (Mod_Int a, Mod_Int b) {return a.val == b.val;}constexpr friend inline bool operator != (Mod_Int a, Mod_Int b) {return a.val != b.val;}protected:T val;};using mint = Mod_Int<>;constexpr mint operator ""_m (unsigned long long x) {return mint(x);}constexpr mint operator ""_mod (unsigned long long x) {return mint(x);}
}using namespace std;
using namespace Mod_Int_Class;
using namespace Bit_Tree_Class;using tree_t = RQuery_Bit_Tree<mint, prefix, std::plus<mint>{}, std::minus<mint>{}, gen_empty_v<mint>, N << 1>;tree_t yzh[3];constexpr mint inv2 = 1_mod / 2;int n, L[N], R[N], ll[N], rr[N];
int real[N << 1], V;
mint ans;signed main() {#ifndef XuYuemingfreopen("rng.in", "r", stdin);freopen("rng.out", "w", stdout);#endifscanf("%d", &n);for (int i = 1; i <= n; ++i) {scanf("%d%d", &L[i], &R[i]);real[++V] = L[i], real[++V] = R[i];}sort(real + 1, real + V + 1);V = unique(real + 1, real + V + 1) - real - 1;for (int i: {0, 1, 2}) yzh[i].init(V);for (int i = 1; i <= n; ++i) {ll[i] = lower_bound(real + 1, real + V + 1, L[i]) - real;rr[i] = lower_bound(real + 1, real + V + 1, R[i]) - real;}for (int i = n; i >= 1; --i) {mint inv_len = 1_mod / (R[i] - L[i]);auto calc = [&inv_len] (int x, int p) -> mint {mint res = 0;res += yzh[0].query(p, V) * x * x * inv2;res += yzh[1].query(1, p - 1) * x;res -= yzh[2].query(1, p - 1) * inv2;return res * inv_len;};ans += calc(R[i], rr[i]);ans -= calc(L[i], ll[i]);static auto update = [] (int x, int p, mint val) -> void {yzh[0].modify(p, val);yzh[1].modify(p, val * x);yzh[2].modify(p, val * x * x);};update(R[i], rr[i],  inv_len);update(L[i], ll[i], -inv_len);}printf("%d", ans.raw());return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/804064.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wpf ToggleButton选中效果和一个登录界面

先看效果 我修改了ToggleButton的ControlTemplate,在ContentPresenter外面加了4个Border,控制4个Border的位置在ControlTemplate的左上、右上、左下、右下,选中时,触发4个边框的BorderThickness <Setter Property="BorderThickness&qu…

WindowSystemEvent

Qt中为WindowSystemEvent事件定义了处理函数Handler,通过宏定义和模版来声明定义 ---- QT_DEFINE_QPA_EVENT_HANDLER Matches (25 in 1 files) ---- qwindowsysteminterface.cpp (gui\kernel) line 199 : #define QT_DEFINE_QPA_EVENT_HANDLER(ReturnType, HandlerName, ...) …

基础数据结构之递归

递归 1) 概述 定义 计算机科学中,递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集In computer science, recursion is a method of solving a computational problem where the solution depends on solutions to smaller instances of the same probl…

JAVA的数组基本用法

array 在声明数组变量时,需要指出数组类型和数组变量名,例如int[] a;不过这条语句只是声明了变量a,并没有将a初始化为一个真正的数组。应该使用new操作符来创建数组。 int[] a = int[100]或者var a = new int[100]数组长度不要求是常数 但是一旦创建了数组,就不能再改变它的…

Unity DatePicker用法,实现UI的日期/时间选择器功能

前言 用Unity3d做一个类似于选时间段,查询数据并展示统计UI的功能 插件 https://assetstore.unity.com/packages/tools/gui/datepicker-for-unityui-68264 样例效果 弹出日期选择器时间范围选择器包含类型 Shared Calendar 共享的日历,这个就是几个选择器共用一个日历来选择时…

正三棱台

正三棱台的相关知识点前情概要 正三棱台的概念,表面积,体积公式,引申 动态演示结合上图,你能说出正三棱台的各部分的名称吗?你能自行画出正三棱台的图形吗? 典例剖析 【2025届高三质检一试题】已知正三棱台 \(ABC-A_1B_1C_1\) 的上底面积为 \(\sqrt{3}\),下底面积为 \(4…

【VMware vCenter】升级到 vCenter Server 8.0 U3b 后 vSphere Client 出现卡死和不响应等问题的解决方法。

最近 VMware 发布了 VMSA-2024-0019 安全通告,更新并修复了 CVE-2024-38812 和 CVE-2024-38813 编号中发现的 vCenter Server 漏洞,可能很多人都已经更新了,我也将自己的实验环境更新到了说明中所修复的版本,vCenter Server 8.0 U3b,内部版本号 24262322。但是,更新之后使…

vscode设置python解释器以及函数无法点击跳转问题

1.下载插件 1.1 Python1.2 Pylance1.3 Remote-SSH2.设置本地/远程python解释器 2.1本地设置 2-1-1 设置解释器路径设置自定义python解释器路径,mac快捷键command + p> python: select interpreter选择或者输入解释器2-1-2 查看设置结果设置完python-venv路径后,打开py脚本…

老毛子、H大固件wan口修改为lan口

事由 因路由器只有一个wan口两个lan口。无线桥接(非AP模式)之后wan口也就没有用了,两个lan口也不够我用,索性将wan桥接为lan。另外:解释一下为何说我桥接不说修改,修改对外行对结果来说的状态,内部命令行专业来说其实就是桥接命令 需求和操作结果 wan口修改为lan口、无线…

布客沉思录(二)合伙人的不作为以及GenAI的新机会

合伙人的不作为————需要做但是没有做的规划翻译并校对了 FreeLearning VKDoc iBooker 三个系列技术教程 √ 制作大量源码解析 √ 制作了视频合成工具 √ 制作了大量玄学视频,普及玄学知识 √ 制作了大量量化教程 √ 探索并实现了开放式两性关系 √ 制作大量视频普及开放式…

第一次结对作业

这个作业属于哪个课程 软件工程2024这个作业要求在哪里 2024秋软件工程结对作业(第一次之需求分析和原型设计)这个作业的目标 学习使用原型软件,辅助完成软件工程的前期任务学号 102201427结对成员学号:102201427、102201426 原型链接:Find You Team一、阅读《构建之法》后…

decimal,float和double的区别是什么?

原文链接:https://blog.csdn.net/hellojoy/article/details/118105569 表示小数的一共有三种类型:float是单精度,double是双精度,decimal是数字型,它们所占的内存空间不一样,表示的位数也不一样。 1、精度:float单精度小数部分能精确到小数点后面6位,用 32 位二进制进…