Codeforces-Round-849-Div-4

注意: \color{red}{注意:} 注意: 个人博客传送门

A. Codeforces Checking

思路:

  • 直接枚举,或者用库函数查找

时间复杂度: O ( 1 ) O(1) O(1)

void solve() {
    std::string s = "codeforces";
    char c;
    std::cin >> c;

    std::cout << (s.find(c) != -1 ? "YES" : "NO") << "\n";
}

B. Following Directions

思路:

  • 根据给定的字符串指令模拟,观察在这个过程中是否经过糖果所在位置即可

时间复杂度: O ( n ) O(n) O(n)

void solve() {
    int n;
    std::cin >> n;

    std::string s;
    std::cin >> s;

    bool ok = false;
    int A = 0, B = 0;
    for (int i = 0; i < n; i++) {
        if (s[i] == 'U') {
            A++;
        } else if (s[i] == 'D') {
            A--;
        } else if (s[i] == 'L') {
            B--;
        } else {
            B++;
        }
        if (A == 1 && B == 1) {
            ok = true;
        }
    }
    std::cout << (ok ? "YES\n" : "NO\n");
}

C. Prepend and Append

思路:

  • 直接双指针,分别从头尾扫描,直到出现两个字符都相同就停止

时间复杂度: O ( n ) O(n) O(n)

void solve() {
    int n;
    std::cin >> n;

    std::string s;
    std::cin >> s;

    int len = n;
    for (int i = 0, j = n - 1; i <= j; ) {
        if (s[i] ^ s[j]) {
            i++, j--;
            len -= 2;
        } else {
            break;
        }
    }
    std::cout << len << "\n";
}

D. Distinct Split

题目大意:对于一个字符的价值,我们将其叫做 f ( s ) f(s) f(s),其定义为:一个字符串中字符出现的种类数。现在,我们可以把字符串 s s s,分为两个子串 a , b a, b a,b,求 f ( a ) + f ( b ) f(a) + f(b) f(a)+f(b) 的最大价值。

思路:

  • 我们可以用双指针,分别从前后扫描,记录从前向后与从后向前的目前子串的种类数,然后我们枚举边界,直接取 m a x max max 即可

时间复杂度: O ( n ) O(n) O(n)

void solve() {
    int n;
    std::cin >> n;

    std::string s;
    std::cin >> s;

    std::set<char> A, B;
    std::vector<int> a(n + 1), b(n + 1);
    for (int i = 0, j = n - 1; i < n; i++, j--) {
        A.insert(s[i]);
        B.insert(s[j]);
        a[i] = A.size();
        b[j] = B.size();
    }

    int max = -1;
    for (int i = 0; i + 1 < n; i++) {
        max = std::max(max, a[i] + b[i + 1]);
    }
    std::cout << max << "\n";
}

E. Negatives and Positives

思路:

  • 由于是改变两个相邻的位置,那么我们一定可以让至少 n − 1 n - 1 n1 个数都是正数。
  • 如果负数的个数为奇数:那么我们可以贪心的使得最小的那个数为负数,这样可以使得答案最大。那么,答案就是 Σ i = 1 n ∣ a i ∣ − 2 × m i n ( ∣ a i ∣ ) \Sigma_{i = 1}^{n}|a_i| - 2 \times min(|a_i|) Σi=1nai2×min(ai) ,为啥是 2 × m i n ( ∣ a i ∣ ) 2 \times min(|a_i|) 2×min(ai) 呢?因为我们求 Σ i = 1 n ∣ a i ∣ \Sigma_{i = 1}^{n}|a_i| Σi=1nai 时,多加了一个 m i n ( ∣ a i ∣ ) min(|a_i|) min(ai),所以要多减去一个。
  • 如果负数的个数为偶数:那么我们可以让所有的数都是正数,直接输出所有元素的绝对值之和即可。

时间复杂度: O ( n ) O(n) O(n)

void solve() {
    int n;
    std::cin >> n;

    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }

    i64 neg = 0, sum = 0;
    for (int i = 0; i < n; i++) {
        if (a[i] < 0) {
            neg++;
            a[i] = -a[i];
        }
        sum += a[i];
    }
    i64 min = *min_element(a.begin(), a.end());
    if (neg & 1) {
        std::cout << sum - 2 * min << "\n";
    } else {
        std::cout << sum << "\n";
    }
}

F. Range Update Point Query

思路:

  • 我是直接用线段树写的,这题涉及到区间修改单点查询,可以直接用线段树做,每个节点记得开一个bool标记,如果 ≤ 10 \le 10 10 就不能在进行修改了。

时间复杂度: O ( n + q × l o g n ) O(n + q \times logn) O(n+q×logn)

constexpr int N = 2E5 + 10;
class SegmentTree {
public:
    int n;
    std::vector<int> a;
    struct node {
        int l, r;
        int val;
        bool ok;
    }tr[N << 2];

    SegmentTree() {}
    SegmentTree(std::vector<int> init_) {
        init(init_);
    }
    void init(std::vector<int> init_) {
        a = init_;
        n = a.size();
        build(1, 1, n);
    }

    void pushup(node &u, node &l, node &r) {
        u.ok = l.ok & r.ok;
    }

    void pushup(int u) {
        pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
    }

    int cal(int x) {
        int res = 0;
        while (x) {
            res += x % 10;
            x /= 10;
        }
        return res;
    }

    void build(int u, int l, int r) {
        tr[u] = {l, r, 0, 0};
        if (l == r) {
            tr[u].val = a[l];
            if (a[l] < 10) {
                tr[u].ok = true;
            }
            return ;
        }
        int mid = l + r >> 1;
        build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }

    void modify(int u, int l, int r) {
        if (tr[u].ok) return ;
        if (tr[u].l == tr[u].r) {
            tr[u].val = cal(tr[u].val);
            if (tr[u].val < 10) tr[u].ok = true;
            return ;
        }
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r);
        if (r > mid) modify(u << 1 | 1, l, r);
        pushup(u);
    }

    int query(int u, int x) {
        if (tr[u].l == tr[u].r) return tr[u].val;
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid) return query(u << 1, x);
        return query(u << 1 | 1, x);
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;

    std::vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        std::cin >> a[i];
    }   
    SegmentTree seg(a);

    while (q--) {
        int op;
        std::cin >> op;

        if (op == 1) {
            int l, r;
            std::cin >> l >> r;

            seg.modify(1, l, r);
        } else {
            int x;
            std::cin >> x;

            std::cout << seg.query(1, x) << "\n";
        }
    }
}

G1. Teleporters (Easy Version)

思路:

  • 直接存一下从起点 0 0 0 到其他位置的花费,然后从小到大排序,直到用完所有的硬币。

时间复杂度: O ( n ) O(n) O(n)

void solve() {
    int n, c;
    std::cin >> n >> c;

    std::vector<int> a(n + 1);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i + 1];
    }

    std::vector<i64> s(n + 1);
    for (int i = 1; i <= n; i++) {
        s[i] = i + a[i];
    }

    std::sort(s.begin() + 1, s.end());

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (c - s[i] < 0) {
            break;
        }
        c -= s[i];
        ans++;
    }
    std::cout << ans << '\n';
}

G2. Teleporters (Hard Version)

思路:

时间复杂度:

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值