闲话 23.3.18

闲话

今天 steam 春促!
大家都买游戏了吗?买了的话,买了什么游戏呢?
反正感觉《量子破碎》22.4 挺香的
《传送门 1/2》4.2 建议入了!

cd 怎么老在群立法典
建议多来点 免得减征

今日推歌:伪善者(covered by 兰音 Reine)
真的很好听
我当时耳虫了 但是想不起标题了 搜歌词找到了
模糊搜索(

杂题

标配五道题?没准慢慢就少了

P6130

给定 \(n\),随机 \(n - 1\)\(\in[0, 1]\) 的实数。把这 \(n - 1\) 个数和 \(0, 1\) 放在 \([0, 1]\) 这段数轴上,会将数轴分割为 \(n\) 个段。

\(T\) 次询问,每个询问给定 \(n, k\),请输出如上程序后得到的第 \(k\) 小的段的长度的期望模 \(998244353\) 意义下的值。

\(1\le k\le n\le 10^7, 1\le T\le 2\times 10^5\)

由于 \([0, 1]\) 区间,期望的值就是概率的值。
接下来只讨论概率,并设第 \(k\) 小线段的长度的随机变量是 \(X_k\)

考虑 \(k = 2\) 的答案如何计算。
考虑一组可能的线段,其中最短的线段长度为 \(x\)。不难发现,我们只需要将最短的线段删除,并将剩下的线段都减去 \(x\) 长度,所要的线段就是这时 \(n - 1\) 条线段里最短的了。这样我们可以将问题的范围缩减 \(1\)
如果我们可以以合适的复杂度缩减答案,剩下的操作就本质相同了。

我们首先需要找到一种复杂度合适的方式计算 \(k = 1\) 的答案。
我们设最短的线段长度为 \(x\),这样所有的线段长度都 \(\ge x\)。此时的情景就是将 \(1 - nx\) 的区间分割为 \(n - 1\) 段,也就是 \(P(X_1 = x) = (1 - nx)^{n - 1}\)
可以知道

\[\begin{aligned} E[X_1] &= \int_0^{1/n} P(X_1 = x)\text dx \\ &= \int_0^{1/n} (1 - nx)^{n - 1}\text dx \\ &= -\frac{1}{n} \int_0^{1/n} (1 - nx)^{n - 1}\text d(1 - nx) \\ &= -\frac{1}{n} \times \frac{1}{n} (1 - nx)^n {\Big\rvert}_0^{1/n} \\ &= \frac{1}{n^2} \end{aligned}\]

然后模拟 \(k = 2\) 的答案计算可以知道 \(E[X_2]\) 就是 \(E[X_1]\) 加上对 \((1 - nE[X_1])\) 的长度取 \(n - 1\) 段的最段段长度。后半部分显然是 \((n - 1)^{-2}\) 乘上长度,从而得到

\[E[X_2] = E[X_1] + \frac{1 - nE[X_1]}{(n - 1)}^2 = \frac{1}{n}\left( \frac{1}{n} + \frac{1}{n - 1}\right) \]

\(E[X_0] = 0\),第 \(k\) 次就是 \(E[X_{k - 1}]\) 加上

\[1 - \sum_{i = 1}^{k - 1} (n - i + 1) (E[X_i] - E[X_{i - 1}]) \]

做个归纳法可以得到

\[E[X_k] = \frac{1}{n} \sum_{i = 1}^k \frac{1}{n - i + 1} \]

可以 \(O(n) - O(1)\)

code
#include <bits/stdc++.h>
using namespace std;
#define multi int _T_; cin >> _T_; for (int TestNo = 1; TestNo <= _T_; ++ TestNo)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
const int N = 1e7 + 10;
int n, k, ans, invsum[N];

signed main() {
	rep(i,1,1e7) invsum[i] = add(invsum[i - 1], inv(i));
    multi { cin >> n >> k, ans ^= mul(inv(n), sub(invsum[n], invsum[n - k])); }
    cout << ans << "\n";
}



AGC032F

有一个圆比萨要切成 \(n\) 块,每刀是一条半径。由于你技术不好,你只会独立均匀地随机 \(n\) 个角度来切。切完之后你会取出圆上相邻的若干块吃掉。

设这个比萨的面积为 \(1\) ,你要找到面积最接近 \(\frac{1}{3}\) 的这若干块,即设你取出的面积为 \(x\),你想要找到 \(\lvert x-\frac{1}{3} \rvert\) 最小的一种方案。求这个最小值的期望,对 \(10^9+7\) 取模。

\(2\le n\le 10^6\)

自适应地,沿用上一题关于 \(E[X_k]\) 的定义。

首先有一个奇妙转化:
我们首先把切的第一刀转到 \(0°\) 位置,然后把 \(120° \sim 240°, 240° \sim 360°\) 对应的两片披萨转到 \(0° \sim 120 °\),然后我们就有一个三片叠在一起的、面积为 \(\frac{1}{3}\) 的披萨片了。切的位置也一样转一下,但是要染个色。如果是且在 \(0° \sim 120 °\) 的染红色;\(120° \sim 240°\) 的减 \(120°\),并染绿色;\(240° \sim 360°\) 的减 \(240°\),并染蓝色。
可以发现度数已经不重要了。这样我们可以转化题意如下:
给定一个 \([0, \frac{1}{3}]\) 的区间,我们可以在其上独立随机选 \(n - 1\) 个点,每次是红/绿/蓝的概率相同,每个位置的概率都相同。再加入两个位于 \(0, 1\) 的点,颜色随意但不同。问任意两个不同色的点的距离最小是多少。

我们不妨把所有 \(n\) 个段拿出来,考虑前 \(k - 1\) 小的段端点同色,这样我们只需要统计 \(E[X_k]\) 并乘上概率。
指定 \(k - 1\) 个段的端点同色的概率是 \([i < n] \dfrac{1}{3^i}\),因为段端点同色的概率互不相干,为 \(\dfrac{1}{3}\),且由于 \(0, 1\) 两点颜色不同,同色段数最大为 \(n - 1\)。因此答案恰好为 \(k\) 的概率是 \(\dfrac{1}{3^{k - 1}} - [i < n] \dfrac{1}{3^k}\)

答案即为

\[\frac{1}{3} \sum_{k = 1}^n\left(\frac{1}{3^{k - 1}} - [i < n] \dfrac{1}{3^k}\right) E[X_k] = \frac{1}{3} \sum_{i = 1}^n \frac{1}{3^i(n - i + 1)} \]

Submission.



P4749

给定 \(n\) 个长度为 \(7\) 的数,第 \(i\) 个为 \(a_i\)。可以执行任意多次如下操作:

  • 选择两个端点 \(l\le r\)\(\forall l\le i\le r\),将 \(a_i\) 的数位旋转任意位。例如可以操作使得 \(1234567\to 4567123\)。注意每次操作对每个数所旋转的方向和位数相同。

请找到最小的操作次数,使得每个数都取到可能的最大值。

\(1\le n\le 500\)

首先剔除形如 \(\overline{aaaaaaa}\) 的数。

我们可以确定每个数需要的旋转次数,记为 \(b_i\)。这样可以转化题意:给序列 \(b\),每次选一段子区间,模 \(7\) 意义下对每个数加 \(1\le v \le 6\),问使得 \(\max b_i = 0\) 的最小操作次数。

这看着就很差分。考虑差分序列是 \(c_i \equiv b_i - b_{i - 1} \pmod 7\),我们可以转化题意:给序列 \(c\),每次可以选择 \(i < j\)\(1\le v\le 6\),模 \(7\) 意义下对 \(c_i\)\(v\)\(c_j\)\(v\);或者选单点 \(i\)\(1\le v\le 6\),模 \(7\) 意义下对 \(c_i\)\(v\)。问使得 \(\max c_i = 0\) 的最小操作次数。

考虑把 \(c_i\) 按值分组。\(c_i = 0\) 的可以不处理,剩下的就是 \(1\sim 6\)了。
可以发现,如果按 \((1, 6), (2, 5), (3, 4)\) 分组的话很赚,因为一加一减定会清除一个,这方案一定不劣。这样我们最后只会剩下三种数,设他们是 \(a, b, c\)

构造最后的方案可以考虑选择 \(i\)\(a_i\) 放进多重集 \(S\),我们需要的就是 \(\sum_{a\in S} a \equiv 0 \pmod 7\),这需要 \(|S| - 1\) 次操作。不妨先统计 \(\sum |S|\),我们随后计算最大的 \(\sum 1\)
考虑 dp。设 \(f(i, j, k)\) 为选了 \(i\)\(a\)\(j\)\(b\)\(k\)\(c\)。考虑当 \(ai + bj + ck \equiv 0 \pmod 7\) 时可以新建一个组,以及此时的答案可以向三维分别 \(+1\) 的位置贡献,我们很容易写出转移方程。

总时间复杂度 \(O(n^3)\)

code
#include <bits/stdc++.h>
using namespace std; 
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 5e2 + 10;
int n, a[N][7], mx[N], cnt, buk[N], ans, f[N][N][N];

int main() {
	cin >> n;
	rep(i,1,n) cin >> a[i][0];
	rep(i,1,n) if (a[i][0] % 1111111 != 0) a[++ cnt][0] = a[i][0];
	n = cnt;
	rep(i,1,n) rep(j,1,6) {
		a[i][j] = (a[i][j - 1] % 1000000) * 10 + a[i][j - 1] / 1e6;
		if (a[i][mx[i]] < a[i][j]) mx[i] = j;
	}
	rep(i,1,n) buk[(mx[i] - mx[i - 1] + 7) % 7] ++;
	int bnd[3] = { abs(buk[6] - buk[1]), abs(buk[5] - buk[2]), abs(buk[4] - buk[3]) };
	int mxv[3] = { (buk[1] > buk[6] ? 1 : 6), (buk[2] > buk[5] ? 2 : 5), (buk[3] > buk[4] ? 3 : 4) };
	ans += max(buk[1], buk[6]) + max(buk[2], buk[5]) + max(buk[3], buk[4]);
	rep(i,0,bnd[0]) rep(j,0,bnd[1]) rep(k,0,bnd[2]) {
		f[i][j][k] += ((i * mxv[0] + j * mxv[1] + k * mxv[2]) % 7 == 0);
		f[i + 1][j][k] = max(f[i + 1][j][k], f[i][j][k]);
		f[i][j + 1][k] = max(f[i][j + 1][k], f[i][j][k]);
		f[i][j][k + 1] = max(f[i][j][k + 1], f[i][j][k]);
	} cout << ans + 1 - f[bnd[0]][bnd[1]][bnd[2]] << '\n';
}



ARC067E

给定 \(A,B,C,D\)。有 \(n\) 个有标号人类,现在要将他们分成若干组 \(\langle a\rangle\),满足:

  • \(\forall i, \ A\le a_i\le B\)

  • \(F_v = \sum_{i} [a_i = v]\)\(\forall i, \ C\le F_i\le D\)

计数本质不同的分组方案数。两种方案本质不同当且仅当存在两个人使得在第一种方案中他们在同一组,而在第二种方案中不是。答案对 \(10^9+7\)取模。

\(1\le n\le 10^3, 1\le A\le B\le n, 1\le C\le D\le n\)

水题。

考虑从小到大枚举组的人数和对应组数。设 \(f(i, j)\) 为考虑了 \(A\sim i\) 的人数,已经放了 \(j\) 个人,转移枚举当前组大小 \(i\) 的个数 \(k\),可以得到

\[f(i, j) = \sum_{ik\le j} \binom{n - j + ik}{i k} f(i - 1, j - ik) g(i, k) \]

其中 \(g(i, k)\)\(ik\) 个人组成 \(k\) 个大小为 \(i\) 的组的方案数。这也就是多重组合数

\[g(i, k) = \frac{1}{k!} \binom{ik}{i, i, \dots, i} \]

下面是 \(k\)\(i\)

Submission.



CF464E

给定一张 \(n\) 个点,\(m\) 条边的无向图,每条边的边权为 \(2^{x_i}\),求 \(s\)\(t\) 的最短路,结果对 \(10^9+7\) 取模。

\(n, m, x \leq 10^5\)

这也是个老题了(
现在才写掉(

这是什么?

《论洛谷的稳定性》

这三份是同一份代码。

image

\(x\)\(n\) 同阶,下面考虑值域 \(O(n)\)

考虑直接用迪杰斯特拉跑。如果我是迪傑你會愛我嗎

考虑有啥操作。
往一个大二进制数里加 1;查询两个大二进制数的大小关系。

考虑用可持久化线段树维护数位。
第一个操作由于总是 \(u\to v\)\(+2^k\),如果我们可以每次只增加 \(O(\log n)\) 个线段树节点,我们总可以通过可持久化线段树的结构用 \(O(m\log n)\) 的空间复杂度获得每个点的数位情况。同样的,如果单次操作是 \(O(\log n)\) 的,在这里的时间复杂度就是 \(O(m\log n)\)
我们需要的是什么?得到 \(k\) 开始向上的极长连续 1 段,并把这段置零,再插入一个 1。前半部分可以先查出 \([0, k - 1]\) 段的 1 个数,再在线段树上二分得到。复杂度 \(O(\log n)\)。置零可以预处理一棵全 0 的满线段树,再把指针适时指到上面即可。插入 1 显然。
这样我们可以 \(O(m\log n)\) 地维护第一个操作。

第二个操作也很简单了。我们需要的是这两个数/字符串的极长公共高位下第一位哪个是 1。这个可以维护区间哈希值,\(O(\log n)\) 地在线段树上二分得到。
这里的哈希可以设 \(\text{base} = 2, \text{mod} = 10^9 + 7\),这样根节点的哈希值恰好是 \(s\to\) 这个点的最短路。

用到了 dij,需要在堆里作最多 \(O(m\log n)\) 次比较,单次比较是 \(O(\log n)\) 的,因此总时间复杂度 \(O(m\log^2 n)\)。可以通过压位获得更好的常数。

Submission.

哦 今天没有多项式!

posted @ 2023-03-18 18:51  joke3579  阅读(95)  评论(3编辑  收藏  举报