Educational Codeforces Round 173

Educational Codeforces Round 173

C

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

D

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

题目转化为求使得 |ab| 最大的 a,b[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;
		}

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

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

举个例子,我们要使 gcd(n,b)1b=2,3,4, 都不成立,n=2×3×5×7×,只有 logn 项。但是反观 b 的增长代价是很小的,b 增长 1a 基本上就要乘上一个质数。

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

代码298220001

E

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

代码298246149

F

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

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

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

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

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

另一方面,当 L12 的时候,根据鸽巢原理,(122)=66>64,也就是有 aiaj=saxay=s,我们的答案不会超过 4

所以对于 12L51 的情况,我们可以去枚举这样的 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(502)

对于 L<12 的情况,我们直接 212 枚举每个数选还是不选。

综上,时间复杂度 O(q(50logn+502+212))

代码298305541

UPD AT 2024/12/25(13:13):经指正,上面这个做法的复杂度是 O(q(50logn+502+12×212)) 次方的,我少考虑了枚举 212 种可能后计算的复杂度。

后经过思考,对于 6n11 的情况,应该可以强行再分讨做 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(50logn+502+64×50+6×26))

因为感觉分讨的有点复杂,并且加上维护 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(50logn+64×7×50)),但似乎 hack 不掉。hack 记录

G

没看。

就到这。

posted @   lingfunny  阅读(157)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示