赛中过题:ABEG。

A - Car Show

给定一个长为 $n$ 的颜色序列 $\{a_i\}$,问有多少段区间出现了所有的颜色?

分析

双指针。对于右端点 $r$,若临界的左端点是 $l$,那么 $[1, l]$ 都是合法的。

队友签的,代码没有。

B - Two Frogs

在一个长为 $n$ 的池塘中,可以从第 $i$ 个荷叶跳到第 $[i + 1, i + a_i]$ 个荷叶上。

若两个青蛙从 $1$ 开始,每个荷叶上随机往后跳,问相同步数到达第 $n$ 个荷叶的期望。

分析

显然 DP。设 $DP(i, j)$ 为跳 $i$ 次跳到第 $j$ 个荷叶上的概率,往后刷表即可。

int main() {
	int n;
	cin >> n;
	vector<int> v(n + 1);
	vector<Z> iv(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> v[i];
		iv[i] = Z(v[i]).inv();
	}
	vector<Z> dp(n + 1);
	dp[1] = 1;
	Z ans = 0;
	for (int i = 1; i <= n; i++) {
		vector<Z> ndp(n + 1);
		auto add = [&](int u, Z x) {
			if (u <= n) 
				ndp[u] += x;
		};
		for (int j = 1; j <= n; j++) {
			Z u = dp[j] * iv[j];
			add(j + 1, u);
			add(j + v[j] + 1, -u);
		}
		for (int j = 1; j <= n; j++) {
			ndp[j] += ndp[j - 1];
		}
		dp = ndp;
		ans += dp[n] * dp[n];
	}
	cout << ans;
	return 0;
}

E - Longest Increasing Subsequence

构造一个长为 $n$ 的排列,使得其恰好有 $m$ 个最长上升子序列。

分析

考虑二进制。我们可以在序列最后放置两个较大的数,使得 LIS 恰好翻倍。

但是若当前为为 $1$,我们需要考虑怎么才能恰好加 $1$ 而又不影响后面。

可以考虑放置一些较小的数,使得其只可能与较小的数形成 LIS,并且后面仍可继承翻倍。

我为了方便编写,使用 front = 60back = -60,最后离散化一下就是排列。

void solve() {
	ll n;
	cin >> n;
	vector<int> v;
	int front = 60, back = -60;
	bool f = true;
	int cnt = 0, back_begin = back;
	for (int i = 31; i >= 0; i--) {
		if ((1ll << i) > n) {
			continue;
		} else if (f) {
			v.push_back(back);
			back += 1;
			cnt += 1;
			f = false;
			continue;
		}
		v.push_back(front + 1);
		v.push_back(front);
		front += 2;
		if ((n >> i) & 1) {
			while (back - back_begin <= cnt) {
				v.push_back(back++);
			}
		}
		cnt++;
	}
	auto ret = func(v);
	cout << ret.size() << '\n';
	for (auto ri : ret) {
		cout << ri << ' ';
	}
	cout << '\n';
}

F - Matrix and GCD

给定一个 $n \times m$ 的矩阵 $M_{ij}$,其值为 $1, \cdots, nm$ 的排列,求其所有子矩阵的 $\gcd$ 之和。

TODO