Educational Codeforces Round 173

Educational Codeforces Round 173

C

记得是处理一下前缀最大值和最小值,后缀最大值和最小值,最后合并即可。这个有讲解,不多赘述。

D

考虑令 \(A = aG, B=bG\),我们有 \(\gcd(a, b) = 1\)

题目转化为求使得 \(\lvert a - b\rvert\) 最大的 \(a, b\in[L', R']\),满足 \(\gcd(a, b) = 1\)

这个我们不难发现,\(\gcd(p, n) = 1\) 当然 \(n = kp\) 除外。

所以如果我们从小到大枚举 \(a\),从大到小枚举 \(b\),大概率会找到 \(\gcd(a, b) = 1\) 的数对。

我们直接暴力枚举:

for (i64 i = l; i <= r && i - l < lim && i - l < res; ++i)
	for (i64 j = r; j >= i && r - j < lim && i - l + r - j < res; --j)
		if (gcd(i, j) == 1) {
			res = min(res, i - l + r - j);
			L = i, R = j;
		}

这个枚举的复杂度是很低的,我感觉是 \(\log^2\) 的枚举,还有一个 \(\log\) 的求 \(\gcd\),但是常数很小。

不妨假设枚举了 \(a = L'\),这时候 \(\gcd(L', b) = 1\) 显然应该很容易成立。

举个例子,我们要使 \(\gcd(n, b)\neq 1\)\(b=2,3,4,\cdots\) 都不成立,\(n=2\times3\times5\times7\times\cdots\),只有 \(\log n\) 项。但是反观 \(b\) 的增长代价是很小的,\(b\) 增长 \(1\)\(a\) 基本上就要乘上一个质数。

我只能说,感性证明,具体证明应该是可以的。

代码298220001

E

这个考虑直接拆位。给定两个 01 矩阵。
能够把某一行改为 \(0\),某一列改为 \(1\),求能否 A -> B
反着考虑?看一下 \(B\) 是否某行为 \(0\) 或者某列为 \(1\)
如果是,可以把这行/列从矩阵中删除,然后看剩下的矩阵是否对应。
时间复杂度 \(O(T S (n+m)\log V)\)

代码298246149

F

赛时的代码有很多 BUG,不过算法是对的。

首先题目就是求区间中删去若干个数,要求剩下的数异或和为 \(0\),求最多删几个和方案数。

约定:我们下面说的「答案」,指的是保留的数字数量。

首先,我们观察到,当区间长度 \(L\) 满足 \(L>51\) 的时候,根据鸽巢原理,显然存在 \(a_i\oplus a_j=0\),我们只需要考虑答案是 \(2\) 还是 \(1\)

\(1\) 就是有 \(0\)\(2\) 就是有两个数相同,这都很好处理(具体可见代码,存储每个数出现的位置,然后二分)。

另一方面,当 \(L \ge 12\) 的时候,根据鸽巢原理,\(\binom{12}{2} = 66>64\),也就是有 \(a_i\oplus a_j = s\)\(a_x\oplus a_y=s\),我们的答案不会超过 \(4\)

所以对于 \(12\le L\le 51\) 的情况,我们可以去枚举这样的 \(i, j, x, y\),对于 \((i, j)\) 这对,可以用桶,对于 \((x, y)\) 这对,我们直接枚举(钦定 \(i, j < x,y\))。可见代码:

Z ans3 = 0, ans2 = 0, ans4 = 0;
array<Z, 64> cnt, cnt2;
for (int i = l; i <= r; ++i) {
    for (int j = i + 1; j <= r; ++j) {
        ans3 += cnt[a[i] ^ a[j]];
        ans4 += cnt2[a[i] ^ a[j]];
        if ((a[i] ^ a[j]) == 0) ans2 += 1;
    }
    cnt[a[i]] += 1;
    for (int j = l; j < i; ++j)
        cnt2[a[i] ^ a[j]] += 1;
}

这里 ans2, 3, 4 就是选 \(2, 3, 4\) 个数异或和为 \(0\) 的方案数,然后用 cnt[x] 记录前 \(i\) 个数中为 \(x\) 的数的数量,cnt2[x] 记录前 \(i\) 个数中,选两个数的异或和为 \(x\) 的方案数。

时间复杂度 \(O(50^2)\)

对于 \(L<12\) 的情况,我们直接 \(2^{12}\) 枚举每个数选还是不选。

综上,时间复杂度 \(O(q(50\log n + 50^2 + 2^{12}))\)

代码298305541

UPD AT 2024/12/25(13:13):经指正,上面这个做法的复杂度是 \(O(q(50\log n+50^2 + 12\times2^{12}))\) 次方的,我少考虑了枚举 \(2^{12}\) 种可能后计算的复杂度。

后经过思考,对于 \(6 ≤ n ≤ 11\) 的情况,应该可以强行再分讨做 \(64n\) 的转移,维护 cnt3

Z ans3 = 0, ans2 = 0, ans4 = 0, ans5 = 0;
array<Z, 64> cnt, cnt2, cnt3;
for (int i = l; i <= r; ++i) {
    for (int j = i + 1; j <= r; ++j) {
        ans3 += cnt[a[i] ^ a[j]];
        ans4 += cnt2[a[i] ^ a[j]];
        ans5 += cnt3[a[i] ^ a[j]]
        if ((a[i] ^ a[j]) == 0) ans2 += 1;
    }
    for (int v = 0; v < 64; ++v)
        cnt3[v ^ a[i]] += cnt2[v];
    for (int j = l; j < i; ++j)
        cnt2[a[i] ^ a[j]] += 1;
    cnt[a[i]] += 1;
}

时间复杂度为 \(O(q(50\log n+50^2+64\times50 + 6\times2^6))\)

因为感觉分讨的有点复杂,并且加上维护 cnt3 的启发,我想可以用 f[i][x] 维护保留 \(i\) 个数,异或和为 \(x\) 的方案数解决本题,dp 的代码见下:

f[0][0] = g[0][0] = 1;
for (int i = l; i <= r; ++i)
    for (int k = 7; k; --k) {
        for (int v = 0; v < 64; ++v) {
            f[k][v ^ a[i]] += f[k - 1][v];
            g[k][v ^ a[i]] |= g[k - 1][v];
        }
    }

提交记录298360108,本做法的时间复杂度为 \(O(q(50\log n + 64\times 7\times 50))\),但似乎 hack 不掉。hack 记录

G

没看。

就到这。

posted @ 2024-12-25 01:17  lingfunny  阅读(173)  评论(0)    收藏  举报