Codeforces Round 905 (Div. 3) 补题报告

1 AC情况

ABCDEFG1G2
Accepted \color{green}\texttt{Accepted} Accepted Accepted \color{green}\texttt{Accepted} Accepted Accepted \color{green}\texttt{Accepted} Accepted Accepted \color{green}\texttt{Accepted} Accepted Accepted \color{green}\texttt{Accepted} Accepted---

2 题解

A. Morning

Problem - A - Codeforces | Morning - 洛谷

题目描述

输入 t t t 组数据。

每组数据有一个四位密码。现在密码输入设备上有一个数列1234567890,初始时光标指向1

1 1 1 秒内,你可以:

  • 按下光标以显示当前数字;
  • 将光标移动到任何相邻的数字。

请计算输入给定的四位密码所需的最少秒数。

题解

模拟即可,注意把0看做10来处理,这样从数字 i i i 移动到数字 j j j 所需的秒数就是 ∣ i − j ∣ \left|i - j\right| ij,最后再加上显示数字的时间 4 4 4 即可。

代码如下:

#include <bits/stdc++.h>
#define endl '\n'
#define file(FILENAME) freopen(FILENAME ".in", "r", stdin), freopen(FILENAME ".out", "w", stdout)
#define CLOSE ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, t;
int main() {
    CLOSE;
    cin >> t;
    while (t--) {
        cin >> n;
        int a = n / 1000, b = n / 100 % 10, c = n / 10 % 10, d = n % 10;  //拆分数字
        if (a == 0) a = 10;  //10替换0
        if (b == 0) b = 10;
        if (c == 0) c = 10;
        if (d == 0) d = 10;
        int ans = 4 + abs(a - 1) + abs(b - a) + abs(c - b) + abs(d - c);  //移动时间+显示时间
        cout << ans << endl; 
    }
    return 0;
}

B. Chemistry

Problem - B - Codeforces | Chemistry - 洛谷

题目描述

输入 t t t 组数据。

每次输入 n n n k k k,和一个仅包含小写字母的字符串 s s s ∣ s ∣ = n \left|s\right| = n s=n)。问在 s s s 中删除 k ( 0 ≤ k < n ) k(0\le k < n) k(0k<n) 个字符后,将 s s s 重新排列,能否构成一个回文串。

题解

回文串的特征:

  • 最多只存在一个字母出现次数为奇数;
  • 其余字母出现次数均为偶数。

我们可以从出现奇数次的字母入手,如果出现奇数次,删去一个,使它成为偶数;不能删了,就记录下奇数的个数。

如果最后出现奇数次的字母的个数大于 1 1 1,那么一定不是回文串。

代码如下:

#include <bits/stdc++.h>
#define endl '\n'
#define file(FILENAME) \
    freopen(FILENAME ".in", "r", stdin), freopen(FILENAME ".out", "w", stdout)
#define CLOSE                    \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, k, t, cnt[N];
char s[N];
int main() {
    CLOSE;
    cin >> t;
    while (t--) {
        memset(cnt, 0, sizeof cnt);
        cin >> n >> k;
        cin >> s;
        for (int i = 0; i < n; i++)  //记录出现次数
            cnt[s[i]]++;
        int flag = 0;
        for (int i = 'a'; i <= 'z'; i++) {
            if (cnt[i] % 2 != 0) {  //出现奇数次
                if (k) {  //能删则删
                    k--;
                    cnt[i]--;
                } else  //不能删,记录个数
                    flag++;
            }
        }
        cout << (flag <= 1 ? "YES\n" : "NO\n");
    }
    return 0;
}

C. Raspberries

Problem - C - Codeforces | Raspberries - 洛谷

题目描述

输入 t t t 组数据。

每次给定数组 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,,an 和一个数 k ( 2 ≤ k ≤ 5 ) k(2\le k\le 5) k(2k5)

每次操作你可以照顾到一个索引 i ( 1 ≤ i ≤ n ) i(1\le i\le n) i(1in),令 a i = a i + 1 a_i=a_i+1 ai=ai+1

问经过若干次操作后,能否使 ∏ i = 1 n a i m o d    k = 0 \prod_{i=1}^n a_i \mod k = 0 i=1naimodk=0

题解

观察发现, k k k 的取值范围是 2 ∼ 5 2\sim 5 25,除去 4 = 2 × 2 4 = 2\times 2 4=2×2 以外,其他数分解质因数都还是本身。

分类讨论:

  • k ∈ { 2 , 3 , 5 } k \in \{2,3,5\} k{2,3,5}:找到一个 d m i n ( a i + d i ≡ 0 ( m o d    k ) ( 1 ≤ i ≤ n ) ) d_{min}(a_i+d_i\equiv 0 (\mod k)(1\le i\le n)) dmin(ai+di0(modk)(1in)),也就是找到最小的一个大于 a i a_i ai 且与它最近的 k k k 的倍数与 a i a_i ai 的差,则可知 d m i n = min ⁡ ( ⌈ a i k ⌉ k − a i ) d_{min}= \min\left(\lceil\frac{a_i}{k}\rceil k - a_i\right) dmin=min(kaikai)

  • k = 4 k = 4 k=4:有一下几种情况:

    1. 存在 a i m o d    4 = 0 ( 1 ≤ i ≤ n ) a_i\mod 4=0(1\le i\le n) aimod4=0(1in),答案为 0 0 0
    2. 存在 a i m o d    2 = 0 , a j m o d    2 = 0 ( 1 ≤ i , j ≤ n , i ≠ j ) a_i\mod 2 = 0,a_j\mod 2=0(1\le i,j\le n,i\ne j) aimod2=0,ajmod2=0(1i,jn,i=j),答案为 0 0 0
    3. 仅存在一个 a i m o d    2 = 0 ( 1 ≤ i ≤ n ) a_i\mod 2=0(1\le i\le n) aimod2=0(1in),再凑出一个偶数即可满足情况2,单位 1 1 1
    4. 存在 a i m o d    4 = 1 ( 1 ≤ i ≤ n ) a_i\mod 4=1(1\le i\le n) aimod4=1(1in),答案为 1 1 1
    5. 全部是奇数,则凑出两个偶数即可满足情况2,答案为 2 2 2

    分别用变量记录各自所需的 a i a_i ai 出现的次数即可,注意判断顺序,答案小的优先

代码如下:

#include <bits/stdc++.h>
#define endl '\n'
#define file(FILENAME) \
    freopen(FILENAME ".in", "r", stdin), freopen(FILENAME ".out", "w", stdout)
#define CLOSE                    \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int t, n, k, a;
int main() {
    CLOSE;
    cin >> t;
    while (t--) {
        cin >> n >> k;
        int ans = 0, p1 = 0, p2 = 0, p3 = 0, p4 = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a;
            if (k != 4)  ans = min(ans, (a / k + (a % k != 0)) * k - a);  //k不是4,找d的最小值
            else {  //k = 4
                if (a % 4 == 0) p1++;  //记录情况1
                else if (a % 2 == 0) p2++;  //记录情况2、3
                else if ((a + 1) % 4 == 0) p3++;  //记录情况4
                else p4++;  //记录情况5
            }
        }
        if (k != 4) cout << ans << endl;
        else {
            if (p1 > 0) cout << 0 << endl;  //判断情况1
            else if (p2 >= 2) cout << 0 << endl;  //判断情况2
            else if (p2 == 1) cout << 1 << endl;  //判断情况3
            else if (p3 > 0) cout << 1 << endl;  //判断情况4
            else cout << 2 << endl;  //判断情况5
        }
    }
    return 0;
}

D. In Love

Problem - D - Codeforces | In Love - 洛谷

题意描述

现在给出 q q q 次操作:

  • +   l   r +\ l\ r + l r:在不去重集合中加入片段 ( l , r ) (l, r) (l,r)
  • −   l   r -\ l\ r  l r:在不去重集合中删除一个片段 ( l , r ) (l, r) (l,r)

每次操作后,判断集合中是否存在一对片段不重合。

题解

我们只需要判断相隔最小的两个片段是否重合即可。如果不重合,则至少存在一对;如果重合,那么其他的片段也必然重合。

而一对不重合的片段 ( l 1 , r 1 ) (l_1,r_1) (l1,r1) ( l 2 , r 2 ) (l_2, r_2) (l2,r2) 满足 r 1 < l 1 r_1<l_1 r1<l1

所以,我们可以分开存储左端点 l l l 和右端点 r r r。如果 r m i n < l m a x r_{min}<l_{max} rmin<lmax ,则存在;反之,不存在。

能够快速排序和删除,还要满足不去重的特性,multiset是最佳的选择。

注意, l l l 每次取最大值,而multiset默认升序排序,但我们知道, ∀ a < b < 0 , − a > − b \forall a<b<0,-a>-b a<b<0,a>b,可以保存 − l -l l 的值,删除使用时取相反数即可。

代码如下:

#include <bits/stdc++.h>
#define endl '\n'
#define file(FILENAME) \
    freopen(FILENAME ".in", "r", stdin), freopen(FILENAME ".out", "w", stdout)
#define CLOSE                    \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, l, r;
map<int, int> visl, visr;
char k;
multiset<int> L, R;
int main() {
    CLOSE;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> k >> l >> r;
        if (k == '+') {
            L.insert(-l);
            visl[l]++;
            R.insert(r);
            visr[r]++;
        } else {
            int t = L.erase(-l);
            t = R.erase(r);
            visl[l]--, visr[r]--;
            if (visl[l]) L.insert(-l);
            if (visr[r]) R.insert(r);
        }
        cout << (-(*L.begin()) > *R.begin() ? "YES\n" : "NO\n");
    }
    return 0;
}

E. Look Back

Problem - E - Codeforces | Look Back - 洛谷

题目描述

输入 t t t 组数据。

给定一个数组 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,,an

可进行操作:找到一个索引 i ( 1 ≤ i ≤ n ) i(1\le i\le n) i(1in),令 a i = a i × 2 a_i = a_i\times 2 ai=ai×2

问最少进行多少次操作,能使数组成为一个非递减数组。

题解

L o g i Log_i Logi :表示 a i a_i ai 需要乘上 2 i 2^i 2i(即需要操作 i i i 次), L o g i ∈ N Log_i\in \N LogiN

从左往右对 a i ( 1 ≤ i ≤ n ) a_i(1\le i\le n) ai(1in) 操作。

先令 L o g i = L o g i − 1 ( 2 ≤ i ≤ n ) Log_i=Log_{i-1}(2\le i\le n) Logi=Logi1(2in)

分类讨论:

  • a i > a i − 1 a_i>a_{i - 1} ai>ai1:说明 L o g i Log_i Logi 过大, 要让操作次数尽可能小且仍要满足条件,则设 L o g i Log_i Logi 要减去 k ( k ∈ N ) k(k\in \N) k(kN)
    a i ≥ a i − 1 × 2 k 2 k ≥ a i a i − 1 log ⁡ 2 ( 2 k ) ≥ log ⁡ 2 ( a i a i − 1 ) k ≥ log ⁡ 2 ( a i a i − 1 ) ∵ k ∈ N , a i × 2 L o g i − 1 − k ≥ a i − 1 , ∴ k = ⌊ log ⁡ 2 ( a i a i − 1 ) ⌋ \begin{aligned} a_i&\ge a_{i - 1}\times 2^{k} \\ 2^{k}&\ge \frac{a_{i}}{a_{i-1}} \\ \log_2\left(2^{k}\right)&\ge \log_2\left(\frac{a_{i}}{a_{i-1}}\right) \\ k&\ge \log_2\left(\frac{a_{i}}{a_{i-1}}\right) \\ \because k\in \N,a_i\times 2^{Log_{i - 1}-k}\ge a_{i - 1},\\ \therefore k&= \left\lfloor\log_2\left(\frac{a_{i}}{a_{i-1}}\right)\right\rfloor \end{aligned} ai2klog2(2k)kkN,ai×2Logi1kai1,kai1×2kai1ailog2(ai1ai)log2(ai1ai)=log2(ai1ai)
    注意, L o g i Log_i Logi 不能为负数,所以应是
    L o g i = max ⁡ ( 0 , L o g i − 1 − ⌊ log ⁡ 2 ( a i a i − 1 ) ⌋ ) Log_i=\max\left(0,Log_{i-1}-\left\lfloor\log_2\left(\frac{a_{i}}{a_{i-1}}\right)\right\rfloor\right) Logi=max(0,Logi1log2(ai1ai))

  • a i < a i − 1 a_i<a_i-1 ai<ai1:同理,设 L o g i Log_i Logi 要加上 k ( k ∈ N ) k(k\in \N) k(kN)
    a i × 2 k ≥ a i − 1 2 k ≥ a i − 1 a i log ⁡ 2 ( 2 k ) ≥ log ⁡ 2 ( a i − 1 a i ) k ≥ log ⁡ 2 ( a i − 1 a i ) ∵ k ∈ N , a i × 2 L o g i − 1 + k ≥ a i − 1 , ∴ k = ⌈ log ⁡ 2 ( a i − 1 a i ) ⌉ \begin{aligned} a_i \times 2^{k} &\ge a_{i - 1} \\ 2^{k}&\ge \frac{a_{i - 1}}{a_{i}} \\ \log_2\left(2^{k}\right)&\ge \log_2\left(\frac{a_{i-1}}{a_{i}}\right) \\ k&\ge \log_2\left(\frac{a_{i-1}}{a_{i}}\right) \\ \because k\in \N,a_i\times 2^{Log_{i - 1}+k}\ge a_{i - 1},\\ \therefore k&= \left\lceil\log_2\left(\frac{a_{i-1}}{a_{i}}\right)\right\rceil \end{aligned} ai×2k2klog2(2k)kkN,ai×2Logi1+kai1,kai1aiai1log2(aiai1)log2(aiai1)=log2(aiai1)
    由此可得
    L o g i = max ⁡ ( 0 , L o g i − 1 + ⌈ log ⁡ 2 ( a i − 1 a i ) ⌉ ) Log_i=\max\left(0,Log_{i-1}+\left\lceil\log_2\left(\frac{a_{i-1}}{a_{i}}\right)\right\rceil\right) Logi=max(0,Logi1+log2(aiai1))

∑ i = 1 n L o g i \sum_{i=1}^nLog_i i=1nLogi 就是操作总次数。

代码如下:

#include <bits/stdc++.h>
#define endl '\n'
#define file(FILENAME) \
    freopen(FILENAME ".in", "r", stdin), freopen(FILENAME ".out", "w", stdout)
#define CLOSE                    \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int t, n;
ll a[N], Log[N];
int main() {
    CLOSE;
    cin >> t;
    while (t--) {
        cin >> n;
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            if (i > 1) {
                if (a[i] > a[i - 1])
                    Log[i] =
                        max((ll)0, Log[i - 1] -
                                       (ll)floor(log2(a[i] * 1.0 / a[i - 1])));
                else
                    Log[i] =
                        max((ll)0,
                            Log[i - 1] + (ll)ceil(log2(a[i - 1] * 1.0 / a[i])));
                ans += Log[i];
            }
        }
        cout << ans << endl;
    }
    return 0;
}
  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值