A - Glutton Takahashi
思路:
- 跳过
以下是代码部分,代码参考来源——jiangly
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<string> s(n);
for(int i = 0; i < n; i ++)
cin >> s[i];
for(int i = 1; i < n - 1; i ++)
if(s[i] == "sweet" && s[i - 1] == s[i])
{
cout << "No\n";
return 0;
}
cout << "Yes\n";
return 0;
}
B - Grid Walk
思路:
- 模拟
以下是代码部分,代码来源——jiangly
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int h, w;
cin >> h >> w;
int x, y;
cin >> x >> y;
x --, y --;
vector<string> c(h);
for(int i = 0; i < h; i ++)
cin >> c[i];
string s;
cin >> s;
for(char op : s)
{
int nx = x;
int ny = y;
if(op == 'L')
ny --;
else if(op == 'R')
ny ++;
else if(op == 'U')
nx --;
else
nx ++;
if(nx >= 0 && nx < h && ny >= 0 && ny < w && c[nx][ny] == '.')
x = nx, y = ny;
}
cout << x + 1 << " " << y + 1 << '\n';
return 0;
}
C - Minimum Glutton
思路:
- 跳过
以下是代码部分, 代码参考来源——jiangly
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
i64 x, y;
cin >> n >> x >> y;
vector<int> a(n), b(n);
for(int i = 0; i < n; i ++)
cin >> a[i];
for(int i = 0; i < n; i ++)
cin >> b[i];
int ans = n;
sort(a.begin(), a.end(), greater<>());
sort(b.begin(), b.end(), greater<>());
for(int i = 0; i < n; i ++)
{
x -= a[i];
if(x < 0)
ans = min(ans, i + 1);
}
for(int i = 0; i < n; i ++)
{
y -= b[i];
if(y < 0)
ans = min(ans, i + 1);
}
cout << ans << '\n';
return 0;
}
D - K-th Nearest
思路.1:
- 二分范围d,并二分判断[ b − d , b + d b - d, b + d b−d,b+d]内有几个 a i a_i ai
- 当范围内 a i a_i ai的数量等于 K K K时,则输出范围 d d d
思路步骤:
1.二分所求d的范围
2.对于
[
x
−
d
,
x
+
d
]
[x - d, x + d]
[x−d,x+d]的范围内,查找有几个
a
i
a_i
ai。
3.查找区间内
a
i
a_i
ai的数量可以用二分查找。
4.经过两次二分查找得出d。
以下是代码部分,代码参考来源——jiangly
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, q;
cin >> n >> q;
vector<int> a(n), b(q), k(q);
for(int i = 0; i < n; i ++)
cin >> a[i];
for(int i = 0; i < q; i ++)
cin >> b[i] >> k[i];
sort(a.begin(), a.end());
for(int i = 0; i < q; i ++)
{
int l_d = 0, r_d = 2e8;
while(l_d < r_d)
{
int x = (l_d + r_d) / 2;
int l = b[i] - x;
int r = b[i] + x;
int cnt = upper_bound(a.begin(), a.end(), r) - lower_bound(a.begin(), a.end(), l);
if(cnt >= k[i])
r_d = x;
else l_d = x + 1;
}
cout << l_d << '\n';
}
return 0;
}
思路.2
- 利用 l s t lst lst维护长度为 k k k的区间
- l s t lst lst代表距离 b i b_i bi从小到大的 k i k_i ki个数的剩余部分, l s t − 1 lst - 1 lst−1代表插入一个 a i a_i ai后还要插入的 a i a_i ai的数量。
- 每次往做或者往右插入 l s t / 2 lst / 2 lst/2个
思路步骤:
- 首先从小到大排列 a a a数组。
- 二分查找 a a a数组中距离 b b b最近的位置p。
- l s t = k − 1 lst = k-1 lst=k−1,每次向左或者向右扩展以p为起点的区间。
- 直到区间长度为 k k k,停止扩展。
- 比较区间左边界和右边界,输出较大的那个。
以下是代码部分,代码参考来源——YoSakuraAkina
#include <bits/stdc++.h>
using namespace std;
int a[100009];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, q;
cin >> n >> q;
for (int i = 0; i < n; i++)
cin >> a[i];
//从小到大排序,使其有序
sort(a, a + n);
while (q--)
{
int b, k;
cin >> b >> k;
//查询离b最近的a的位置
int p = lower_bound(a, a + n, b) - a;
p = min(p, n - 1);
//更加精确离b最近的a的位置
if (p > 0 && abs(a[p - 1] - b) < abs(a[p] - b)) p--;
//如果k=1,直接得出结果
if (k == 1)
{
cout << abs(a[p] - b) << '\n';
continue;
}
//一开始,左边右边的边界均为p
//需要插入的a_i为lst = k - 1
int l = p, r = p, lst = k - 1;
while (lst > 1)
{
//利于边界判断
int m1 = l - lst / 2;
int m2 = r + lst / 2;
//如果p在最左边
if (l == 0)
{
r += lst;
lst = 0;
break;
}
//如果p在最右边
if (r == n - 1)
{
l -= lst;
lst = 0;
break;
}
//如果左边界越界
if (m1 < 0)
{
m1 = 0;
//判断应该延长左边界还是右边界
//延长后,更新左边界和右边界
//并更新lst
if (abs(a[m1] - b) < abs(a[m2] - b))
{
lst -= l - m1;
l = m1;
}
else
{
r = m2;
lst -= lst / 2;
}
}
//如果右边界越界
else if (m2 > n - 1)
{
m2 = n - 1;
//判断应该延长左边界还是右边界
if (abs(a[m1] - b) < abs(a[m2] - b))
{
l = m1;
lst -= lst / 2;
}
else
{
lst -= m2 - r;
r = m2;
}
}
//如果均范围合法
else
{
if (abs(a[m1] - b) < abs(a[m2] - b))
l = m1;
else
r = m2;
lst -= lst / 2;
}
}
//如果还需插入一个数字
if (lst == 1)
{
if (l > 0 && abs(a[l - 1] - b) < abs(a[r + 1] - b) || r == n - 1)
l--;
else
r++;
}
//取大的输出
if (abs(a[l] - b) > abs(a[r] - b))
cout << abs(a[l] - b) << '\n';
else
cout << abs(a[r] - b) << '\n';
}
return 0;
}
E - Maximum Glutton
思路:
- dp动态规划
- 定义 d p [ i ] [ j ] = { v } dp[i][j] = \{v\} dp[i][j]={v}
- d p dp dp[道菜的数量][甜度] = {此时最少的咸度}。
这样设定状态,减少时间复杂度。类似于01背包的做法
以下是代码部分,代码参考来源——jiangly
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int N, X, Y;
cin >> N >> X >> Y;
//定义dp数组
//dp[吃的菜的数量][甜度] = {最少的咸度}
//初始化设置咸度为无穷大
vector dp(N + 1, vector<int>(X + 1, Y + 1));
//甜度为0时,咸度必定为0
dp[0][0] = 0;
for(int i = 0; i < N; i ++)
{
int A, B;
cin >> A >> B;
//前i餐,甜度为x到A的状态转移
for(int c = i; c >= 0; c --)
for(int d = X; d >= A; d --)
dp[c + 1][d] = min(dp[c + 1][d], dp[c][d - A] + B);
}
int ans = 0;
//找寻甜度和咸度均达标的时候的最大的i的值
for(int i = 0; i < N; i ++)
for(int x = 0; x < X; x ++)
if(dp[i][x] <= Y)
//注意下标的统一
ans = max(ans, i + 1);
cout << ans << '\n';
return 0;
}