欢迎访问博客阅读(更新每场cf div2 A-D, atcoder A-E, leetcode, acwing周赛)
A. Deletions of Two Adjacent Letters
Code
void solve()
{
string s; char c;
cin >> s >> c;
bool flag = false;
for (int i = 0; i < s.length(); i++)
if (s[i] == c && i % 2 == 0)
{
flag = true;
break;
}
if (flag) puts("YES");
else puts("NO");
}
B. DIV + MOD
Code
void solve()
{
int l, r, a;
cin >> l >> r >> a;
int res = r / a + r % a;
int m = r / a * a - 1;
if (m >= l) res = max(res, m / a + m % a);
cout << res << endl;
}
C. Weight of the System of Nested Segments (排序)
解题思路
输出的最小权值其实就是m - 2 * n 个 权值最小的点的和
OS: 很简单的一道题,但是一开始一直以为输出的是端点坐标,结果竟然是“输入编号”
Code
struct point
{
int id, x, w;
};
bool cmpw(point a, point b) {return a.w < b.w;}
bool cmpx(point a, point b) {return a.x < b.x;}
void solve()
{
int n, m, sum = 0; cin >> n >> m;
vector<point> points(m);
for (int i = 0; i < m; i++) cin >> points[i].x >> points[i].w, points[i].id = i + 1; // 输入的同时要存入"输入编号(id)"
sort(points.begin(), points.end(), cmpw); // 按权值从小到大排序
for (int i = 0; i < m; i++)
if (i < 2 * n) sum += points[i].w; // 前2 * n个小的权值相加
else points.pop_back(); // 后面的全部删掉,这样后面排序就只剩用到的点了
sort(points.begin(), points.end(), cmpx); // 按坐标从小到大排序
cout << sum << endl;
// 一首一末输出“输入编号”
for (int i = 0; i < n; i++) cout << points[i].id << ' ' << points[2 * n - i - 1].id << endl;
cout << endl;
}
D. Twist the Permutation(数学/逆向思维)
解题思路
TIP1:答案总是存在的
TIP2:通过进行反向操作来还原
Code
void solve()
{
int n, x, pos[N],res[N]; cin >> n;
for (int i = 1; i <= n; i++) cin >> x, pos[x] = i; // 记录每个数的最后位置
for (int i = n; i > 0; i--)
{
/*
计算出从原来的位置循环了几次,如i = 6, 假设pos[i] = 4,
则pos[i] % i = 4 % 6 = 4 次
*/
res[i] = pos[i] % i;
for (int j = 1; j < i; j++)
pos[j] = (pos[j] + i - res[i]) % i; // 这里是还原操作
/*
(i - res[i]) 实则是还原位置的次数,如i = 6, pos[i] = 4, 那么需要6 - 4 = 2次
即pos = pos + 2 = 4 + 2 = 6, 完成还原
*/
}
for (int i = 1; i <= n; i++) cout << res[i] << ' ';
cout << '\n';
}
E. Rescheduling the Exam(贪心)
Code
int n, d;
int work(vector<int> &b) // 用来找到最佳方案
{
int minn = 0x3f3f3f3f, maxn = -1;
for (int i = 1; i < n; i++)
{
minn = min(minn, b[i] - b[i - 1] - 1);
maxn = max(maxn, b[i] - b[i - 1] - 1);
}
/*两种方案:1.放在最后一天, 2. 放在最大区间的中间
因为题目要求结果尽可能大,所以这两种方案取较大值;
然后再跟遍历过程中找到的最小区间取较小值
*/
return min(minn, max(d - b.back() - 1, (maxn - 1) / 2));
}
void solve()
{
cin >> n >> d;
vector<int> a(n + 1);
int min_val = d, min_pos = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] - a[i - 1] - 1 < min_val) // 找到最短休息时间的位置和值
{
min_val = a[i] - a[i - 1] - 1;
min_pos = i;
}
}
vector<int> b;
for (int i = 0; i <= n; i++) // 因为要计算第一门考试之前的休息时间,所以要加入0
if (i != min_pos) b.push_back(a[i]);
int res = work(b);
if (min_pos > 1) b[min_pos - 1] = a[min_pos];
/* 这里这么做是因为一开始找到的[min_pos - 1, min_pos]这个区间由两个端点构成,
第一次work计算了a[min_pos - 1]这个点得出的最佳方案,
那么第二次就用a[min_pos]替换a[min_pos - 1],计算它得出的最佳方案
*/
cout << max(res, work(b)) << endl; // 对两种端点得出的最佳方案取较大值
}
or2