前言
hello!各位C友们好呀,博主又来写题解了,这场周赛,博主只写了前三题(hhh, 第四题是真不会),这一场周赛说难也难,说简单也简单,难在第4题太难想了,简单在前三题知道相应的知识还是比较好想的,那么废话不多说,直接进入今天的正题吧!
正文
1.3020. 子集中元素的最大数量
- 题目链接:子集中元素的最大数量
- 这道题,不知道各位wa了几次呢?我是wa了3次,喜提15分钟罚时。
- 题目思路:
- 哈希表记录元素出现次数。
- 初始化ans为1的出现次数的最大奇数次(坑1,因为1的不管多少次方都是1,避免陷入死循环)。
- 遍历数组,从小到大暴力枚举最长的字集中的最大数量。
- 说明:这里的最大数量必然为奇数次,如果枚举的数的出现次数大于等于2时,就有接着枚举的可能,可以接着枚举,如果枚举的数的出现次数等于1,则无法接着枚举,因此最后的数量为枚举的数的种类 * 2 + 1。
- 坑2 : 如果枚举是用平方的话,可能会爆int,因此需要判断一下。
- 细节: 这里从小到大每次都乘本身,其实枚举的次数是很小的。
- 实现代码:
class Solution {
public:
int maximumLength(vector<int>& nums)
{
unordered_map<int,int> hash;
for(auto e : nums)
hash[e]++;
//坑1:初始值为1的最大奇数次长度。
int ans = hash[1] - (hash[1] % 2 ^ 1);
int MAX = 1e9;
for(auto e : nums)
{
if(e == 1) continue; //避免陷入死循环
long long val = e;
int res = 0,len = 0;
//坑2: val 可能会爆int
while(val <= MAX && hash.count(val))
{
res = 2 * len + 1;
if(hash[val] == 1)
break;
len++;
val *= val;
}
ans = max(res,ans);
}
return ans;
}
};
2.3021. Alice 和 Bob 玩鲜花游戏
- 题目链接:Alice 和 Bob 玩鲜花游戏
- 题目思路:
- 这是一道阅读理解题,把题目意思读明白了,这道题其实很简单。
- 关键点:Alice先走,每个人必须每次摘一朵,先摘完的赢。—— 只要花的总数是奇数即可。
小小数学知识点:
- 奇 + 奇 = 偶, 奇 - 奇 = 偶, 偶 + 偶 = 偶, 偶 - 偶 = 偶。
- 奇 + 偶 = 奇,奇 - 偶 = 奇。
- 有[1,n] 个数,有 (n + 1) / 2个奇数,n / 2 个偶数。
- 因此:我们只需要枚举(x,y), x能取多少个奇数,y能取多少个偶数,相乘得情况1,x能取多少个偶数,y能取多少个奇数,相乘得情况2,两种情况之和即为结果。
- 实现代码:
class Solution {
public:
long long flowerGame(int n, int m)
{
long long x = n,y = m;
long long ans1 = ((x + 1) / 2) * (y / 2);
long long ans2 = (x / 2) *((y + 1) / 2);
return ans1 + ans2;
}
};
- 细节:注意用 () 表明计算的优先顺序,因为计算机有上下取整的问题,不带括号算起来是有误差的。
- 小小思考技巧:
- 实现代码:
class Solution {
public:
long long flowerGame(int n, int m)
{
return (long long)n * m / 2;
}
};
3.3022. 给定操作次数内使剩余元素的或值最小
- 题目链接:给定操作次数内使剩余元素的或值最小
- 题目思路:
- 此题难在难想出思路,想出来倒还是比较简单的,代码也比较好写。好写归好写,博主在此题坐牢了将近一个小时,也憋不出半句代码,hhh。
- 从二进制的角度思考,或运算,只要有1就会保留,但是我们可以通过与操作,通过相邻的0通过与1按位与变为0。
- 且要使或值最小,我们要从高位的1,进行逐步验证看是否能在k次操作内变为0。这里就需要分析得出一个重要结论:
- 如果某一段数字能变为0,那么就为那一段长度减1。
- 如果某一段数字不能变为0,那么就为那那一段的长度。
- 特殊的:如果那一段长度全为1,则需要nums.length,但 k < nums.length,因此无需考虑这一情况。
- 高位按位与的顺序会对低位产生影响,因此我们应保留高位能枚举的1位,继续往下枚举看是否可能为在k次操作内变为0。也就是在高位至多k次按位与变为0的前提下,看低位是否也能在至多k次按位与变为0。
- 如果不能变为0,则答案中必然有这一位,将这一位按位或到答案上,同时删除这一位不能枚举的高位。
- 如果能变为0,则答案中这一位为0。保留这一位继续往下枚举即可。
class Solution {
public:
int minOrAfterOperations(vector<int>& nums, int k)
{
int ans = 0,mask = 0;
for(int i = 29; i >= 0; i--)
{
mask |= 1 << i;
int res = -1; //补码全为1,用于初始化第一个数
int cnt = 0;
for(auto num : nums)
{
res &= num & mask;
if(res) cnt++;
else
{
/*
变为0之后,无需再管,避免后面&的结果一直为0,需要再进行初始化
之后看下一段1变为0的操作次数。
*/
res = -1;
}
}
if(cnt > k)
{
ans |= (1 << i); //此位的1必定在答案中出现。
mask ^= (1 << i);
//删除不能变为0的一位,以防止对后面的操作产生影响。
}
}
return ans;
}
};
总结
本场周赛考察了哈希枚举,奇偶性,位运算(从高位枚举填写答案)。希望本篇文章对大家有所帮助吧!
尾序
我是舜华,期待与你的下一次相遇!