AcWing第59场周赛
思路:前缀和
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N];
int n;
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n;
int ans = 0;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++)
{
a[i] += a[i - 1];
ans = min(ans, a[i]);
}
cout << a[n ] -ans;
return 0;
}
思路:这题。。。。本以为只是找到一个最小的质因数然后相除得到的结果就是答案,当时一直以为是正确的,然后没有做出来。后来看了题解后直到一个数减去它的最小质因子后为偶数,2位最小的质因子。这题的数据最大为10^10,会爆int,所以数据要用long long(或者long)来存储。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
long long n;
cin >> n;
long long ans = 0;
bool st = 0;
for(long long i = 2; i * i <= n; i ++)
{
if(n % i == 0)
{
n -= i;
ans ++;
st = 1;
break;
}
}
if(!st) n = 0, ans ++;
ans += n / 2;
cout << ans;
return 0;
}
力扣第301场周赛
第一题:6112. 装满杯子需要的最短总时长 - 力扣(LeetCode)
思路:模拟,每次将最多的两个减去1,直到只有一个数大于0。
代码
class Solution {
public:
int fillCups(vector<int>& amount) {
priority_queue<int> q;
for(auto i : amount)
{
if(i > 0) q.push(i);
}
int ans = 0;
while(q.size() > 1)
{
int a = q.top(); q.pop();
int b = q.top(); q.pop();
a --, b --;
ans ++;
if(a > 0) q.push(a);
if(b > 0) q.push(b);
}
if(q.size() == 1) ans += q.top();
return ans;
}
};
第二题:6113. 无限集中的最小数字 - 力扣(LeetCode)
思路:用set来存储,set是从小到到排列的,所以每次返回最小值并移除可以直接返回并移除set的第一个元素。
代码
class SmallestInfiniteSet {
public:
set<int> s;
SmallestInfiniteSet() {
for(int i = 1; i <= 1000; i ++) s.insert(i);
}
int popSmallest() {
int it = *s.begin();
s.erase(s.begin());
return it;
}
void addBack(int num) {
s.insert(num);
}
};
/**
* Your SmallestInfiniteSet object will be instantiated and called as such:
* SmallestInfiniteSet* obj = new SmallestInfiniteSet();
* int param_1 = obj->popSmallest();
* obj->addBack(num);
*/
第三题:6114. 移动片段得到字符串 - 力扣(LeetCode)
思路:将两个字符串(只比较L和R)进行比较,如果两个字符相同且都为L,那么start的L的位置一定要大于等于target中L的位置,否则无法从start到target,如果两个字符相同且都为R,那么start中R的位置一定要小于等于target中R的位置,否则无法从start到target。将start和target中的字符(L和R)逐一比较。
代码
class Solution {
public:
bool canChange(string start, string target) {
int n = start.size(), m = target.size();
int i, j;
for(i = 0, j = 0; i < n && j < m; i ++, j ++)
{
int a = i, b = j;
while(a < n && start[a] == '_') a ++;
while(b < m && target[b] == '_') b ++;
if(a == n && b == m) return true;
if(start[a] == 'L' && target[b] == 'L' && a >= b) i = a, j = b;
else if(start[a] == 'R' && target[b] == 'R' && a <= b) i = a, j = b;
else return false;
}
while(i < n && start[i] == '_') i ++;
while(j < n && target[j] == '_') j ++;
return (i == n) && (j == m);
}
};
力扣第82场双周赛
第一题:6116. 计算布尔二叉树的值 - 力扣(LeetCode)
思路:递归
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool evaluateTree(TreeNode* root) {
if(root->val == 2) return evaluateTree(root->left) || evaluateTree(root->right);
else if(root->val == 3) return evaluateTree(root->left) && evaluateTree(root->right);
return root->val;
}
};
第二题:6117. 坐上公交的最晚时间 - 力扣(LeetCode)
思路:模拟。我在写这题的时候是用的指针模拟的,用指针模拟的话要很多的判定条件(这个我当时真的快要崩溃了,wa了13次,整个人都不好了)。后来看了别人的代码,用数组和队列模拟的,这个最后判断的条件比指针少很多。
代码
class Solution {
public:
int latestTimeCatchTheBus(vector<int>& buses, vector<int>& passengers, int capacity) {
queue<int> q;
set<int> s;
sort(buses.begin(), buses.end());
sort(passengers.begin(), passengers.end());
int n = buses.size();
vector<vector<int>> d(n);
for(auto i : passengers) q.push(i), s.insert(i);
for(int i = 0; i < n; i ++)
{
while(d[i].size() < capacity && q.size() && q.front() <= buses[i])
{
d[i].push_back(q.front());
q.pop();
}
}
int ans;
if(d[n - 1].size() < capacity) ans = buses[n - 1];
else ans = d[n - 1][capacity - 1];
while(1)
{
if(!s.count(ans)) break;
ans --;
}
return ans;
}
};
第三题:2333. 最小差值平方和 - 力扣(LeetCode)
思路:根据题目意思,可以看作用一个数组来存储nums1与nums2每个元素的差的绝对值,然后对这个数组中的数做多可以进行k1 + k2次减1操作,进行操作之后得到的数组的每个数的平方和的最小值是多少。为了得到最小值肯定是从最大的值开始减。首先我先想到的就是用大根堆来存储,每次将第一个元素减1,如果减1后 如果大于0就存入大根堆。然后这样超时了。这个需要做一些优化,因为有一些相同的数,所以可以用大根堆来存储数和数的个数。
类似于这样的一座山砍掉面积为k1 + k2。
代码
class Solution {
public:
typedef long long LL;
long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) {
unordered_map<int, int> mp;
for(int i = 0; i < nums1.size(); i ++)
{
int a = abs(nums1[i] - nums2[i]);
if(a) mp[a] ++;
}
priority_queue<pair<int, int>> q;
for(auto [x, y] : mp) q.push({x, y}), cout << x << " " << y << endl;
int cnt = k1 + k2;
while(q.size() && cnt)
{
auto [x, y] = q.top(); q.pop();
if(q.size())
{
auto [xx, yy] = q.top(); q.pop();
int a = x - xx, b = y;
if(a * b <= cnt)
{
cnt -= a * b;
q.push({xx, yy + y});
}
else
{
int aa = cnt / b;
int bb = cnt - aa * b;
cnt = 0;
q.push({xx, yy});
q.push({x - aa, y - bb});
q.push({x - aa - 1, bb});
}
}
else
{
if(x * y <= cnt) break;
int a = cnt / y;
int b = cnt - a * y;
cnt = 0;
x -= a;
q.push({x, y - b});
if(x - 1) q.push({x - 1, b});
}
}
LL ans = 0;
while(q.size())
{
auto [x, y] = q.top(); q.pop();
cout << x << " " << y << endl;
ans += (LL)x * x * y;
}
return ans;
}
};
这个的时间复杂度有点高,后来看了一下y总的力扣单周赛讲解发现这个可以二分。
代码
class Solution {
public:
bool check(int mid, vector<int> & nums1, int cnt)
{
long long sum = 0;
for(auto i : nums1)
{
if(i >= mid) sum += i - mid;
}
return sum <= cnt;
}
long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) {
long long sum = 0;
for(int i = 0; i < nums1.size(); i ++)
{
nums1[i] = abs(nums1[i] - nums2[i]);
sum += nums1[i];
}
int cnt = k1 + k2;
if(sum <= cnt) return 0;
sort(nums1.begin(), nums1.end());
reverse(nums1.begin(), nums1.end());
int l = 0, r = nums1[0];
while(l < r)
{
int mid = (l + r ) >> 1;
if(check(mid, nums1, cnt)) r = mid;
else l = mid + 1;
}
int a = 0;
for(auto i : nums1)
{
if(i >= l) a += i - l;
}
a = cnt - a;
long long ans = 0;
for(auto i : nums1)
{
if(i >= l)
{
if(a) ans += (long long)pow(l - 1, 2), a --;
else ans += (long long)pow(l, 2);
}
else ans += (long long)pow(i, 2);
}
return ans;
}
};