TLX-TROC29D - VIIbit Explorer

哪个印度尼西亚 wmc 出的题。。。

手玩+看到这个 $k$ 的数据范围大概才得到这东西操作到特定情况后不管怎么操作,答案都不会增加。

所以不妨考虑构造一个最优秀的方案。

我们显然希望构造出形如 $2^n - 1 = (1111\dots\dots 1)_2$ 的形式,而这个权值显然是两倍两倍增加的,所以考虑配对。

也就是形如 $i \text{ xor } j = 2^n - 1$ 的 $i, j$ 应该被配对。

此时出现一个问题是,$(11100)_2$ 还有 $(1100)_2$ 这两个的最优搭档显然应该是 $(11)_2$。

不难注意到,如果我们从 bit 数最多的开始贪心选择,出现配对重复的两个数 $i, j$ 中,bit 小的那一方必然会在 bit 大的那一方同 bit 的某一个数配对时被配对到。

比如上面的例子:$(1100)_2$ 向上会被 $(10011)_2$ 配对到。

所以我们不需要担心会被选漏,上面没有下面一定有。

唯一要考虑的特殊情况就是形如 $j = 0$ 的 $i$,特判一下即可。

复杂度 $O(n)$,似乎可以 log。

// Enonya

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

#define int long long

const int si = 1e6 + 10;

int n, k, vis[si], mx[100], g[si];

signed main() {

	int ans = 0;
	cin >> n >> k;
	for(int i = 0; i < 24; ++i) {
		mx[i + 1] = (1ll << (i + 1)) - 1;
	}
	
	g[1] = 0;
	for(int i = 2; i <= n; ++i) {
		g[i] = g[i >> 1] + 1;
	}

	int tot = 0;
	for(int i = n; i >= 1; --i) {
		if(tot == k) break;
		if(vis[i] != 0) continue; 
		int ma = mx[g[i] + 1];
		if((i ^ ma) <= 0) continue;
		ans += ma * 2, vis[i] = 1, vis[i ^ ma] = 1, tot++;
	}

	cout << ans << endl;
	
	return 0;
}

TLX-TROC21D - Piranha Plan

直接对序列做不是很好搞。

值域上做可能对头一点,但是也不是很好弄。

最麻烦的地方就是在于这个 $P + Q$ 很迷惑,先尝试写出来会比较好。

不妨钦定一个已经被我们操作完的序列

$Q$ 就应该是此时所有满足 $a_i = a_j - 1$ 的 $a_i$ 元素的数量之和。

$P$ 呢?应该是我们把所有满足 $a_i = a_j - 1$ 的 $i, j$ 调整所花费的代价。

那这俩玩意儿加起来有没有什么性质?

有的,有的。

你注意到调整显然就是调整满足 $a_i = a_j - 1$ 的这样一对关系,因为 朋友 显然会从小的开始执行操作,所以不妨把 $a_j$ 全部调整为 $a_i$。那 $P$ 就是所有这样的 $a_j$ 的数量。

$Q$ 则是 $n -$ 剩下部分即调整后的 $a_i, a_j$ 的数量。

那么其实就是,钦定一些食人鱼不被吃掉,求这些数量的最大值即可。

做一个值域上的简单 dp 即可(以不超过 $x$ 为指标)

// Enonya

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

#define int long long

const int si = 2e5 + 10;

int n, a[si], c[si], dp[si];

signed main() {

	cin >> n;
	for(int i = 1; i <= n; ++i) {
		cin >> a[i], c[a[i]] += 1;
	}
	for(int i = 2; i <= 100002; ++i) {
		dp[i] = max(dp[i - 1], dp[i - 2] + c[i]);
	}
	cout << n - dp[100001] << endl;

	return 0;
}
Copyright @Enonya, 转载请注明出处