Codeforces 1847 A-F

题面

A B C D E F
难度:红 橙 黄 蓝 紫 紫

题解

B

题目大意:找到一组分割方法,使得 i=1k(&j=liriaj) 取得最小值时使 k 最大,输出 k。其中 & 表示按位与操作。

题目分析:

& 0 1
0 0 0
1 0 1

不难发现,因为 aN,所以 (1)a,ba&b (2)a+ba&b且对于公式 (2),当且仅当 a=b=0 时取等。
因此考虑贪心。设 x=&i=1nai。对于 x>0 的 情况,根据 (2),分成一组的和是最优的,因此 k=1;对于 x=0 的情况,只要将原数组分为几段区间按位与都为 0 的区间即可。
代码略。

C

题目大意:对于数组 a,它的前 n 个数由题目给定,而 ai(i>n)=j=ki1aj,其中 k 不确定,1ki1,而 表示按位异或。求 a 中元素的最大可能值。
这套题怎么这么多位运算?
题目分析:

0 1
0 0 1
1 1 0

题目给定 ai<28(1in),所以由按位与的定义得到全体 ai<28
ap=i=lp1ai,则 ap+1=i=kpai=(i=kp1ai)ap=(i=kp1ai)(i=lp1ai)=i=min(k,l)max(k,l)1ai
于是问题转化为求最大字段异或。又因为异或运算满足结合律,可以用前缀异或加速。
问题再次转化为:求前缀异或数组中,任意两数异或的最大值。
由于 ai<28,所以前缀异或数组中元素的值也在这个值域内。因此考虑用桶记录前缀数组中的数,然后与前缀数组进行“配对”求异或值。时间复杂度 O(28×n),可以通过这道题。

#include <bits/stdc++.h>
using namespace std;
int t, n, a[100010];
bool x[100010];
int main() {
scanf("%d", &t);
while (t--) {
memset(x, 0, sizeof(x));
scanf("%d", &n);
int ans = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] ^= a[i - 1];
x[a[i]] = 1;
ans = max(ans, a[i]);
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 256; j++) {
if (x[j]) {
ans = max(ans, a[i] ^ j);
}
}
}
printf("%d\n", ans);
}
return 0;
}

D

从这里开始难度陡增。
(未完)

posted @   cwkapn  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示