文章目录
A. Morning
思路:将 0 0 0 替换成 10 10 10,然后遍历这字符串,用变量 p r e pre pre 维护上一个字符的值,最后求出总耗的时间
void solve()
{
string s; cin >> s;
int cnt = 0;
int pre = 1;
for (int i = 0; i < s.size(); i++) {
int m = s[i] - '0';
if (m == 0) m = 10;
cnt += abs(m - pre);
pre = m;
}
cout << cnt + 4 << endl;
}
写的时候思路有点乱,当时是将 0 0 0 特别判断,直接将 0 0 0 变成 10 10 10 就更加直观且方便
B. Chemistry
思路:当删成一个奇数长度和只有一个奇数字母的时候,如果要删掉的字母数量大于 k k k,那么则输出 " N O " "NO" "NO",否则输出 " Y E S " "YES" "YES"
void solve()
{
int n, k;
cin >> n >> k;
string s;
cin >> s;
map<int, int> mp;
for (int i = 0; i < s.size(); i++) {
mp[s[i]-'a'] ++;//统计每个数的个数
}
int cnt = 0;
for (auto x : mp) {
if (x.second % 2 == 1)cnt++;//奇数个数的数量
}
int ans = 0;//奇数的话删到只剩一个,默认是删完ans个后的串是奇数串,此时剩一个奇数
if (cnt > 1) ans = cnt - 1;//删掉只剩一个奇数
if (ans > k) puts("NO");//
else puts("YES");
}
C. Raspberries
思路:特判 k = = 4 k == 4 k==4 的时候,由于 k = = 4 k == 4 k==4 的因子可以有两个 2 2 2 组成,所以我们在遍历数组的时候同时要判断是否存在 2 2 2 的因子,存在两个的时候, k = = 4 k == 4 k==4 的最小操作数为 0 0 0
void solve()
{
int n, k;
cin >> n >> k;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
int ans = INF, cnt = 0;
if (k == 4)
{
for (int i = 1; i <= n; i++)
{
if (a[i] % 2 == 0)
{
cnt++;
}
if (a[i] % k == 0)
{
ans = 0;
}
ans = min(ans, k - (a[i] % k));
}
if (cnt >= 2)
{
cout << 0 << endl;
}
else
{
cout << min(ans, 2 - cnt) << endl;
}
}
else
{
for (int i = 1; i <= n; i++)
{
if (a[i] % k == 0)
{
ans = 0;
}
ans = min(ans, k - (a[i] % k));
}
cout << ans << endl;
}
}
D. In Love
思路:考察的是数据结构,对 m u l t i s e t multiset multiset 的熟练度,关于集合,能否保证集合群当中存在一组线段集合不想交,就看是否存在,右边界的集合最小和左边界的集合最大若是存在 r < l r < l r<l,即保证一直存在这个合法解
const int INF = 0x3f3f3f3f;
int b[N];
multiset<int> r;//右边边界最小
multiset<int, greater<int>> l;//左边边界最大
/*
---r----l---- 即存在
*/
void solve()
{
char c[2];
int L, R;
cin >> c >> L >> R;
if (*c == '+') {
l.insert(L);
r.insert(R);
}
else {
l.erase(l.find(L));
r.erase(r.find(R));
}
if (l.empty() && r.empty()) {
puts("NO");
}
else if (*l.begin() > *r.begin()) {
puts("YES");
}
else {
puts("NO");
}
}
E. Look Back
思路:将改变大小的形式转换为 a i ∗ 2 x a_i * 2 ^x ai∗2x,维护相邻两个数的前缀 x x x,相邻两个数的大小谁能变得谁大谁小的操作数是固定的,同时将前面相邻的数的操作前缀进行相加即是当前两个相邻数的操作数,将所有的 x x x 相加即是答案。
void solve()
{
int n; cin >> n;
vector<int > a(n + 1);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
ll ans = 0,cnt= 0;
for (int i = 1; i < n; i++) {
int l = a[i - 1], r = a[i], ct = 0;
while (l < r) ct--, l *= 2;
while (l > r) ct++, r *= 2;
cnt = max(0ll, cnt + ct);
ans += cnt;
}
cout << ans << endl;
}
F. You Are So Beautiful
思路:要求只有一种方法选择一个序列,那么保证没有重复的,就需要找到数字出现的最后一个位置,数字最前出现的位置是这个子序列多一种情况下,后面再出现的情况是会出现重复。因此整个过程只考虑数字第一次出现的位置和最后一次出现的位置。(子序列不连续,但是题目要求的 l , r l,r l,r 的范围与长度一致,相当于找子串)
void solve()
{
int n; cin >> n;
vector<int > a(n + 1);
map<int, int> f, e, mp;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
if (mp[a[i]] == 0) {
mp[a[i]] = 1;
f[a[i]] = i;
e[a[i]] = i;
}
else {
e[a[i]] = i;
}
}
ll cnt = 0,ans = 0;
for (int i = 0; i < n; i++) {
if (f[a[i]] == i) {
cnt++;
}
if(e[a[i]] == i) ans += cnt;
}
cout << ans << endl;
}
G2. Dances (Hard Version)
思路:给数组 a a a 排序,每个 a a a 都尽量选择满足要求的尽量小的 b b b ,然后可以发现如果加入的数字小于剩下的最大的数字,那么可以让答案加一,否则答案不变.
void solve()
{
int n, m;
cin >> n >> m;
multiset<int> b;
vector<int> a(n - 1);
for (int i = 0; i < n - 1; i++) cin >> a[i];
for (int i = 0; i < n; i++) {
int x; cin >> x;
b.insert(x);
}
sort(a.begin(), a.end());
int ans = 0;
for (auto x : a) {
auto it = b.upper_bound(x);
if (it != b.end()) {
b.erase(it);
ans += 1;
}
}
ll t = 1ll * ans * m;
int mx = *prev(b.end());
t += min(mx - 1, m);
cout << 1ll * n * m - t << endl;
}