【Codeforces Round #849 (Div. 4)】A~G题解

简介: 笔记

A. Codeforces Checking


题意

给定字符是否是codeforces 当中的一个

思路

调用string类的find方法

代码

void solve() {
  string s = "codeforces";
  string a; cin >> a;
  if (s.find(a) != -1) {
    cout << "YES" << endl;
  } else {
    cout << "NO" << endl; 
  }
}

B. Following Directions


题意

给定一串字符串,形如“LUDR”,问能否按字符串走法从(0,0)途经(1,1)。

思路

直接模拟即可

代码

void solve() {
  cin >> n;
  string s; cin >> s;
  int walk[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
  auto f = [=](char c){
    if (c == 'L') return 3;
    if (c == 'D') return 2;
    if (c == 'R') return 1;
    return 0;
  };
  int x = 0, y = 0;
  for (auto c: s) {
    auto d = f(c); 
    x += walk[d][0];
    y += walk[d][1];
    if (x == 1 && y == 1) { cout << "YES" << endl; return ;}
  }
  cout << "NO" << endl; 
  return ;
}

C. Prepend and Append


题意

给定01串,每次可以删除两侧各一个字符,但是这两个同时删除的字符必需不同,即(01,10)。问最后能剩下的字符串最小值。

思路

贪心,能删则删,维护删除的次数。

代码

void solve() {
  cin >> n;
  string s; cin >> s;
  int cnt = 0;
  for (int i = 0, j = s.sz - 1;  i < j; i++, j--) {
    if (s[i] != s[j]) cnt++;
    else break;
  }
  cout << n - cnt * 2 << endl;
}

D. Distinct Split


进阶一点的相似题型 -> 【传送门】


题意

规定 f ( " a b c " ) f("abc")f("abc") 表示字符串 “abc” 的不同字符数,即f ( " a b c " ) = 3 f("abc")=3f("abc")=3。


现在给定一个字符串 s ss,问:s ss分为两个字符串(a , b a,ba,b)后求值 f ( a ) + f ( b ) f(a) + f(b)f(a)+f(b) 的最大值。


思路

显然需要动态维护一串字符串的不同字符数,那么用 map 维护,当字符数变0需要erase掉当前的键,而 map.size() 就是当前该字符串的不同字符数,即是不同的键的数量。


先预处理整个串的 f ( s ) f(s)f(s)作为后缀,然后正序遍历进行分割,动态增加前缀串,删除后缀串的 map 所维护的键值对。


代码

void solve() {
  cin >> n;
  string s; cin >> s;
  map<char, int> f, g;
  for (auto c: s) g[c]++;
  int res = 0;
  for (int i = 0; i < n; i++) {
    auto c = s[i];
    f[c]++;
    g[c]--;
    if (g[c] == 0) g.erase(c);
    res = max(res, (int)(f.size() + g.size()));
  }
  cout << res << endl;
}

E. Negatives and Positives


题意

1.png


思路

可以发现的性质是,一段区间内的修改实际上等价于区间两侧的修改,即任意位置的一对可以同时变为其相反数。


那么如果数组中有偶数个负数,可以直接全变为正数。


否则数组有奇数个负数,那么第一想法肯定是选最大的负数留下。


但是考虑到会有比该负数的绝对值更小的正数,这样最优应是让这个正数变负。


实现:以上描述实际上就是挑一个绝对值最小的数作为负数处理,前提是当前数组中有奇数个负数。


代码

void solve() {
  cin >> n;
  vi v;
  int sum = 0;
  int cnt = 0;
  rep (i, 1, n) {
    int x; cin >> x;
    if (x < 0) {
      cnt ++;
      x = -x;
    }
    v.pb(x);
    sum += x;
  }
  sort(all(v));
  if (cnt & 1) sum -= 2 * v[0];
  cout << sum << endl;
}

F. Range Update Point Query


题意

数组 a aa,有 q qq 个询问,每次询问如下:


l r:表示 l , r  区间的数进行操作。【操作:a i变为a i

各个数位之和】

2 x:表示输出当前的 a x


思路


代码

线段树

维护当前区间是否还需要更改,即存在 >= 10 的数。

int n, m;
int a[N];
struct node {
    int l, r;
    int val, mx;
} tr[N << 2];
void pushup(int u) {
  tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx);
}
int f(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 = l, tr[u].r = r;
    if(l == r) { tr[u].val = a[l]; tr[u].mx = a[l]; 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].mx < 10) return ;
    if(tr[u].l == tr[u].r) {
        int x = f(a[tr[u].l]);
        a[tr[u].l] = x;
        tr[u].val = x;
        tr[u].mx = x;
        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(x == tr[u].l && x == 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() {
  cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    build(1, 1, n);
    while(m --) {
        int op, l, r;
        cin >> op;
        if(op == 1) {
          cin >> l >> r;
            modify(1, l, r);
        } else {
          int x; cin >> x;
          cout << query(1, x) << endl;
        }
    }
}
  • 树状数组
  • 差分,前缀维护当前更改的次数。预处理每个数的修改。
class BIT {
public:
  BIT() { memset(tr, 0, sizeof tr); }
  int tr[N];
  void add(int x, int v = 1) { for (; x < N; x += x & -x) tr[x] += v; }
  int sum(int x) { int res = 0; for (; x; x -= x & -x) res += tr[x]; return res; }
};
int n, m;
void solve() {
  cin >> n >> m;
  auto f = [=](int x){ int res=0;while(x){res+=x%10;x/=10;}return res;};
  vi v[n + 1];
    for(int i = 1; i <= n; i ++) {
      int x; cin >> x;
      while (1) {
        v[i].pb(x);
        if (x < 10) break;
        x = f(x);
      }
    }
  BIT t;     
    while(m --) {
        int op, l, r;
        cin >> op;
        if(op == 1) {
          cin >> l >> r;
          t.add(l, 1);
          t.add(r + 1, -1);
        } else {
          int x; cin >> x;
          cout << v[x][min(t.sum(x), (int)v[x].sz - 1)] << endl; 
        }
    }
}

G1. Teleporters (Easy Version)


题意

0为原点,1~n有n个数,总共体力k点。在k点体力下,要求能拿到最多几个数。拿数的要求是:从0开始走到x,花费x点体力,从x拿到数返回0,花费a[x]点体力。每次拿完一个数需要返回0点。


思路

贪心


代码

int n, m;
int a[N];
void solve() {
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    a[i] += i;
  }
  sort(a + 1, a + 1 + n);
  int res = 0;
  for (int i = 1; i <= n; i++) {
    if (m >= a[i]) res++, m -= a[i];
  }
  cout << res << endl;
}


相关文章
|
2月前
|
机器学习/深度学习 人工智能 测试技术
Codeforces Round 960 (Div. 2)
Codeforces Round 960 (Div. 2)
|
人工智能 算法 BI
Codeforces Round #179 (Div. 2)A、B、C、D
我们每次加进来的点相当于k,首先需要进行一个双重循环找到k点和所有点之间的最短路径;然后就以k点位判断节点更新之前的k-1个点,时间复杂度降到O(n^3),而暴力解法每次都要进行floyd,时间复杂度为O(n^4);相比之下前述解法考虑到了floyd算法的性质,更好了运用了算法的内质。
57 0
【CodeForces】Codeforces Round 857 (Div. 2) B
【CodeForces】Codeforces Round 857 (Div. 2) B
136 0
Codeforces Round 859 (Div. 4)题解
Codeforces Round 859 (Div. 4)题解
106 0
Codeforces Round 799 (Div. 4)
Codeforces Round 799 (Div. 4)
121 0
【算法题解】Codeforces Round #817 (Div. 4)题解
【算法题解】Codeforces Round #817 (Div. 4)题解
【算法题解】Codeforces Round #817 (Div. 4)题解
|
人工智能 BI
Codeforces Round #805 (Div. 3) 题解
Codeforces Round #805 (Div. 3) 题解
Codeforces Round #805 (Div. 3) 题解