第 27 场 蓝桥月赛
2.蓝桥字符【算法赛】 - 蓝桥云课https://www.lanqiao.cn/problems/20270/learning/?contest_id=250
问题描述
蓝桥杯官方近日收到了一份神秘的包裹,里面包含一个 U 盘和一张纸条,纸条上仅写有一个由小写字母组成的字符串 SS。经过初步检查,U盘内存储的内容似乎与即将到来的蓝桥杯大赛有关,但 U 盘被加密,无法直接访问。根据情报提供方的提示,U盘的密码与字符串 SS 中特定子序列的出现次数密切相关。
具体来说,密码等于字符串 SS 中子序列 lan
的出现次数。这里的子序列是指从字符串 SS 中按顺序选取字符(不一定连续)组成的新字符串。
为了帮助蓝桥杯官方顺利解开 U 盘的密码,你需要编写一个程序,计算字符串 S 中子序列 lan
的出现次数。
输入格式
输入为一个由小写字母组成的字符串 S,长度不超过 1e5。
输出格式
输出一个整数,表示字符串 S 中子序列 lan
的出现次数。
输入样例
lanlan
输出样例
4
说明
在字符串 lanlan
中,子序列 lan
出现了 4 次。具体来说,可以选取以下位置的字符:
- 第 1、2、3个字符(
l
,a
,n
) - 第 1、2、6个字符(
l
,a
,n
) - 第 1、5、6个字符(
l
,a
,n
) - 第 4、5、6个字符(
l
,a
,n
)
有两种做法,第一种是预处理。代码如下:
#include <iostream>
using namespace std;
#define int long long
signed main()
{
int a[100005] = { 0 };
int ncnt = 0;
int ans = 0;
string s;cin >> s;
for (int i = s.size() - 1;i >= 0;--i)
{
a[i] = a[i + 1];
if (s[i] == 'a')
a[i] += ncnt;
else if (s[i] == 'n')
ncnt++;
else continue;
}
for (int i = 0;i < s.size();++i)
{
if (s[i] == 'l')
ans += a[i];
}
cout << ans;
return 0;
}
即我们知道lan一定是按顺序的,既然是这样,那么我们可以遍历数组,把 l 全部找出来并统计在其之后每一个的 a 所对应的在该 a 之后的 n 的个数。这是暴力的做法。当然我们可以把后面我们所说的这个个数预处理出来。令 a[i] 数组代表在数组第 i 个之后的所有 a 的每一个的 a 所对应的在该 a 之后的 n 的个数。那么我们从后往前遍历,记录n的个数,然后找到a时,将n的个数加上去,详细见代码。当然我们也可以从前往后递推,把上述的 n 换成 l 即可。
3.蓝桥大使【算法赛】 - 蓝桥云课https://www.lanqiao.cn/problems/20271/learning/?contest_id=250
问题描述
小蓝和小桥是某学校的蓝桥大使,他们的主要任务是作为宣传人员在校内宣传蓝桥杯比赛。蓝桥杯是一项全国性的编程竞赛,吸引了众多学生参与。为了扩大比赛的影响力,学校决定在每个班级进行宣传,而小蓝和小桥则负责这项工作。
学校共有 n 个班级,每个班级都需要进行宣传。小蓝和小桥可以选择去不同的班级宣传,但为了公平起见,他们决定尽量平均分配任务。具体来说:
- 小蓝将去 ⌊n/2⌋)个班级宣传。
- 小桥将去剩下的 n−⌊n/2⌋个班级宣传。
对于第 ii 个班级:
- 如果小蓝去宣传,他将获得 Ai 元的酬劳。
- 如果小桥去宣传,她将获得 Bi 元的酬劳。
小蓝和小桥希望最大化他们总共获得的酬劳,请你帮他们计算总酬劳最大值是多少?
输入格式
第一行包含一个整数 n(1≤n≤1e5),表示班级的数量。
接下来 n 行,每行包含两个整数 Ai,Bi(1≤Ai,Bi≤1e9),分别表示小蓝和小桥去第 i 个班级宣传时获得的酬劳。
输出格式
输出一个整数表示答案。
输入样例
5
10 20
30 40
100 60
90 80
100 110
输出样例
360
说明
小蓝去第3,4个班级宣传,小桥去第1,2,5个班级宣传,总共可以获得100+90+110+20+40=360元。
可以考虑贪心。对于任意班的酬劳,我们看到希望是越多越好。但两人都有由于次数限制,那么我们就让他们分别去各自能获得最大收益的那几个班。具体思路如下代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
struct dif
{
int ind, diff;//索引与差值
};
bool cmp(dif& a, dif& b)
{
return a.diff < b.diff;
}
signed main()
{
int n;cin >> n;
int ans = 0;
int a[100005], b[100005];
vector<dif> s(n);
for (int i = 0;i < n;++i)
{
cin >> a[i] >> b[i];
s[i].ind = i;
s[i].diff = b[i] - a[i];
}
sort(s.begin(), s.end(), cmp);
for (int i = 0;i < n / 2;++i)
{
ans += a[s[i].ind];
}
for (int i = n / 2;i < n;++i)
{
ans += b[s[i].ind];
}
cout << ans;
return 0;
}
6.备份比赛数据【算法赛】 - 蓝桥云课https://www.lanqiao.cn/problems/20274/learning/?contest_id=250这道题没什么说的,经典的二分答案
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, t;
vector<int> a;
inline bool check(int x)
{
int day = 0;
int temp = 0;
for (int i = 0;i < a.size();++i)
{
temp += a[i];
if (temp > x)
{
if (i % 2)
{
temp = temp - x;
day += temp / x + 1;
temp %= x;
}
else
{
temp = 0;
i--;
day++;
}
}
if (day > t)
return false;
}
return true;
}
signed main()
{
cin >> n >> t;
a.resize(2 * n);
int sum = 0;
for (int i = 0;i < 2 * n;i += 2)
{
cin >> a[i];
sum += a[i];
}
for (int i = 1;i < 2 * n;i += 2)
{
cin >> a[i];
sum += a[i];
}
sum -= a[2 * n - 1];
a.pop_back();
int l = sum / t, r = 3600;
int mid = (l + r) / 2;
while (l < r)//左闭右开区间
{
mid = (l + r) / 2;
if (check(mid))
{
r = mid;
}
else l = mid + 1;
}
if (l >= 3600)
cout << -1;
else cout << l;
return 0;
}