20230711刷题
C. Social Distance
按照题解的方法使用双指针判断出全部是0的字串的长度
放入这堆0的字串的个数为cnt/(k+1)向上取整
对于全是0的情况单独判断
或者0下标0开始,或者0包含最后一个点的情况单独判断
#include <bits/stdc++.h>
#define yes cout<<"YES"<<'\n'
#define no cout<<"NO"<<'\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 100008;
void solve() {
int n, k;
cin >> n >> k;
string s;
cin >> s;
int ans = 0;
int cnt = 0;
for (int i = 0; i < (int)s.size(); i++) {
if (s[i] == '0') {
cnt++;
}
}
if (cnt == n) {//先判断是不是全部都是0
cout << (n + k + 1 - 1) / (k + 1) << '\n';
//n/(k+1)向上取整
return;
}
for (int i = 0; i < n; i++) {
int j = i;//双指针寻找0串
bool flag = false;
while (s[j] == '0' && j < n) {
j++;
flag = true;
}
if (i == 0 || j == n) {
//如果包含第一个点和最后一个点
if (j - i - k > 0) {//当0串的数量大于0的时候
ans += (j - i - k + k + 1 - 1) / (k + 1);//除以k+1向上取整
}
} else {//如果是中间普通的点的话
if (j - i - 2 * k > 0) {
ans += (j - i - 2 * k + k - 1 + 1) / (k + 1);//除以k+1向上取整
}
}
if (flag) {
i = j - 1;//双指针
}
}
cout << ans << '\n';//打印结果
}
int main () {
std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int t;
cin >> t;
while (t) {
solve();
t--;
}
return 0;
}
D. Epic Transformation
使用贪心和优先队列,每次都选取数量最多的两个数进行匹配,直到最后打印结果
让我们用每个字符在字符串中出现的次数来替换它。然后每个操作 - 取两个非零数字并从中减一。最后,我们将只剩下一个非零数字,我们希望将其最小化。我们可以说,我们希望在应用所有操作后最小化最大数量,这意味着我们希望最小化每一步的最大数量。我们得到以下贪婪解决方案 - 每次我们选取出现次数最多的两个字符并删除它们。
#include <bits/stdc++.h>
#define int long long
#define yes cout<<"YES"<<'\n'
#define no cout<<"NO"<<'\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 100008;
void solve() {
priority_queue <PII> q;//优先队列
int n;
cin >> n;
map<int, int> mp;
for (int i = 1; i <= n; i++) {
int b;
cin >> b;
mp[b]++;
}
for (auto a : mp) {//将mp里面的映射放入队列
q.push({a.second, a.first});
//将值放在第一个,键放在第二个
}
int ans = n;//原本有n个答案
while ((int)q.size() >= 2) {//当队列中元素大于2时
auto x = q.top();
q.pop();
auto y = q.top();
q.pop();
//取出最多的两个元素
x.first--;
y.first--;//每个都减去1
ans -= 2;//每次让答案减2
if (x.first != 0) {//如果当前的x.first不为0,继续入队
q.push(x);
}
if (y.first != 0) {
q.push(y);
}
//直到最后
}
cout << ans << '\n';
}
signed main () {
std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int t;
cin >> t;
while (t) {
solve();
t--;
}
return 0;
}
A. Strange Birthday Party
这个题用了贪心算法
记得开long long
先对k进行排序,然后从最后一个开始计算,贪心的加入最后的结果.
最后打印出来.
#include <bits/stdc++.h>
#define int long long
#define yes cout<<"YES"<<'\n'
#define no cout<<"NO"<<'\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 300008;
int a[N];
int c[N];
void solve() {
int n, m;
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
for (int i = 1; i <= m; i++) {
scanf("%lld", &c[i]);
}
sort(a + 1, a + n + 1);//先排序
int idx = 1;//指向c数组的下标
int ans = 0;
for (int i = n; i >= 1; i--) {
if (idx == m + 1) {//如果c数组已经被选择完了
ans += c[a[i]];//直接给现金
continue;
}
if (c[idx] < c[a[i]]) {//否则开始贪心
//如果当前给的现金小于当前的礼物的话,选择礼物
ans += c[idx];//选择买礼物
idx++;
} else {
ans += c[a[i]];//如果当前给的现金大于等于当前的礼物的话,选择现金
}
}
cout << ans << '\n';
}
signed main () {
// std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int t;
cin >> t;
while (t) {
solve();
t--;
}
return 0;
}
C. Rotation Matching
可以看一下官方题解
记录每个b[i]移动到a[i]的位置需要几步,使用map来用步数映射匹配数量
#include <bits/stdc++.h>
#define yes cout<<"YES"<<'\n'
#define no cout<<"NO"<<'\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 200008;
int a[N];
int pos[N];
int b[N];
int main () {
int n;
scanf("%d", &n);
int ans = 0;
map<int, int> mp;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
pos[a[i]] = i;
//当前a[i]所在的位置的下标为i
}
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
//j为b[i]要和a[i]相同要向右移动的步数
int j = pos[b[i]] - i;
if (j < 0) {//如果j为负数就加上n
j += n;
}
mp[j]++;//次数加1
ans = max(ans, mp[j]);//去最大值
}
printf("%d\n", ans);
return 0;
}
A. Triangle
使用勾股定理进行计算,但是要注意不要使用sqrt()避免精度问题
注意某一个点移动之后可能会造成两个点重合的情况要具体判断一下
#include <bits/stdc++.h>
#define yes cout<<"YES"<<'\n'
#define no cout<<"NO"<<'\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 100008;
struct Node {
int x, y;
};
bool judge(Node a, Node b, Node c) {//判断是不是直角三角形的函数
double edge[5];
edge[1] = (b.y - a.y) * (b.y - a.y) + (b.x - a.x) * (b.x - a.x);
edge[2] = (c.y - a.y) * (c.y - a.y) + (c.x - a.x) * (c.x - a.x);
edge[3] = (b.y - c.y) * (b.y - c.y) + (b.x - c.x) * (b.x - c.x);//求出三个边值的平方
sort(edge + 1, edge + 4);//排序
if (edge[1] == 0) {//如果一条边为0,直接返回false
return false;
}
if (edge[1] + edge[2] == edge[3]) {//如果满足勾股定理
return true;
} else {
return false;
}
}
int main () {
Node a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
if (judge(a, b, c)) {//先判断一下
printf("RIGHT\n");
return 0;
}
//判断a点
//移动a点
for (int i = 0; i < 4; i++) {
Node temp;
temp.x = a.x + dx[i];
temp.y = a.y + dy[i];
if (judge(temp, b, c)) {
printf("ALMOST\n");
return 0;
}
}
//判断b点
//移动b点
for (int i = 0; i < 4; i++) {
Node temp;
temp.x = b.x + dx[i];
temp.y = b.y + dy[i];
if (judge(a, temp, c)) {
printf("ALMOST\n");
return 0;
}
}
//判断c点
//移动c点
for (int i = 0; i < 4; i++) {
Node temp;
temp.x = c.x + dx[i];
temp.y = c.y + dy[i];
if (judge(a, b, temp)) {
printf("ALMOST\n");
return 0;
}
}
printf("NEITHER\n");//都不满足
return 0;
}