タイトル: 第338回週間大会
開催日: 2023-03-29 16:31:08
カテゴリー: 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 − sum [ j − 1 ] + sum [ N ] − sum [ j − 1 ] − ( N − j + 1 ) ∗ xt *x - sum[j-1] + sum[N] - sum[j-1] - (N - j + 1) * xt∗バツ−s u m [ j−1 ]+合計[ N ] _ _−s u m [ j−1 ]−( N−j+1 )∗バツ
実施にあたっては、境界判定に注意してください。
#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;
}
};