title: 第 338 场周赛
date: 2023-03-29 16:31:08
categories: Leetcode周赛
mathjax: true
第 338 场周赛
K 件物品的最大和
贪心,直接按照1,0,-1选即可
class Solution {
public:
int kItemsWithMaximumSum(int numOnes, int numZeros, int numNegOnes, int k) {
int res = 0;
if(k<=numOnes) return k;
else if(numOnes+numZeros>=k) return numOnes;
else return numOnes - (k - numOnes - numZeros);
}
};
质数减法运算
先筛出1000以内的质数,因为数值范围比较小,怎么筛都行。因为题目要求严格递减,根据贪心思想,我们让每个数在满足递增的条件下尽可能的小。
class Solution {
public:
bool primeSubOperation(vector<int>& nums) {
vector<int>p;
for(int i=2;i<=1010;++i)
{
int st = 1;
for(int j =2;j*j<=i;++j)
if(i%j == 0) st = 0;
if(st == 1) p.push_back(i);
}
int lst = 0;
for(int i = 0;i<nums.size();++i)
{
int st = 0;
for(int j = p.size()-1;j>=0;j--)
{
if(p[j]< nums[i] && nums[i] - p[j] > lst)
{
lst = nums[i] - p[j];
st = 1;
break;
}
}
if(st == 0)
{
if(nums[i] > lst) lst = nums[i];
else return false;
}
}
return true;
}
};
使数组元素全部相等的最少操作次数
对整数数组排序,若当前要变成x,在排序数组内找到第一个大于等于x的数,这个数的下标记为j,则要变换的次数为: t ∗ x − s u m [ j − 1 ] + s u m [ N ] − s u m [ j − 1 ] − ( N − j + 1 ) ∗ x t *x - sum[j-1] + sum[N] - sum[j-1] - (N - j + 1) * x t∗x−sum[j−1]+sum[N]−sum[j−1]−(N−j+1)∗x
实现的时候注意边界判断。
#include <algorithm>
class Solution {
public:
vector<long long> minOperations(vector<int>& num, vector<int>& queries) {
vector<int>nums = num;
sort(nums.begin(),nums.end());
vector<long long>sum(1000010,0);
for(int i=0;i<nums.size();++i)
if(i == 0)sum[i] =nums[i];
else sum[i] =sum[i-1]+nums[i];
vector<long long>ans;
for(int i=0;i<queries.size();++i)
{
if(nums.size()==1) ans.push_back(abs(queries[i] - nums[0]));
else
{
long long t = lower_bound(nums.begin(),nums.end(),queries[i])-nums.begin();
long long x =0 ,y = 0;
if(t > 0) x = t * queries[i] - sum[t-1];
if(t == 0) y = sum[nums.size()-1] - (nums.size() - t) * queries[i];
else if(t <= nums.size()-1) y = sum[nums.size()-1] - sum[t-1] - (nums.size() - t) * queries[i];
ans.push_back(x + y);
}
}
return ans;
}
};
收集树中金币
不难发现:
- 对于没有金币的叶子(树枝)节点对最终的答案是没有影响的。
- 将所有没有金币的叶子(树枝)删出后,得到一颗新的树,此时不管从哪个节点开始收集,最后的答案的都是一样的
根据上述结论,可以用拓扑排序删去多余的树枝,删除后再跑一遍拓扑排序得到最后的答案。
class Solution {
public:
int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {
const int N = coins.size(),M = edges.size()*2;
vector<int>e(M, 0),h(N, -1),ne(M, 0);
vector<int>d(N, 0),dist(N, 0),st(N, 1);
int idx = 0;
function<void(int, int)> add = [&](int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
};
for(auto p: edges)
{
int a = p[0], b = p[1];
add(a, b), add(b, a);
d[a] ++, d[b] ++;
}
int n = coins.size();
queue<int>q;
for(int i = 0; i < n; i ++ )
if(d[i] == 1 && coins[i] == 0) q.push(i);
while(!q.empty())
{
int p = q.front();
q.pop();
st[p] = 0;
for(int i = h[p]; i!=-1;i=ne[i])
{
int j =e[i];
if(--d[j] == 1 && coins[j] == 0) q.push(j);
}
}
for(int i = 0; i < n; ++ i) d[i] = 0;
for(auto p: edges)
{
int a = p[0], b = p[1];
if(st[a] == 0 || st[b] == 0) continue;
d[a] ++, d[b] ++;
}
while(!q.empty()) q.pop();
for(int i=0;i<n;++i)
if(d[i] == 1 && st[i] == 1)
{
q.push(i);
dist[i] = 0;
}
int mx = -1,mxid = -1;
while(!q.empty())
{
auto p = q.front();
q.pop();
for(int i = h[p];i!=-1;i=ne[i])
{
int j = e[i];
d[j] --;
if(d[j] == 1)
{
q.push(j);
dist[j] = dist[p] + 1;
}
if(dist[j] >= mx) mx = dist[j], mxid = j;
}
}
int cnt = 0;
function<void(int, int)> dfs = [&](int u, int fa)
{
for(int i = h[u];i!=-1;i=ne[i])
{
int j = e[i];
if(j == fa) continue;
if(st[j] == 0) continue;
if(dist[j] < 2) continue;
cnt ++;
dfs(j ,u);
}
};
if(mxid == -1) return 0;
dfs(mxid, -1);
return cnt * 2;
}
};