ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #797 (Div. 3)

2022-06-08 02:02:43  阅读:197  来源: 互联网

标签:797 std le int void mid Codeforces Div define


打工人下班晚了,到家只剩一个小时了,做完最后两题夜宵外卖到了,前面的题先咕咕了。

F. Shifting String

题意

给定一个长度为\(n\)的字符串\(s\)和一个长度为\(n\)的排列\(p\)。

定义乘法:字符串\(s_1s_2\dots s_n\)乘上排列\(p\)等于\(s_{p_1}s_{p_2}\dots s_{p_n}\)。

问经过多少次乘法之后\(s\)首次变回原串?

其中\(1 \le n \le 200\)。

思路

排列可以看成置换,然后就想到拆成多个子群,子群答案的LCM就是答案。

长度为\(l\)的子群最多\(l\)次操作就变回原样了。

然后就是模拟了,复杂度\(O(n^3)\)。

AC代码
// Problem: F. Shifting String
// Contest: Codeforces - Codeforces Round #797 (Div. 3)
// URL: https://codeforces.com/contest/1690/problem/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#define freep(p) p ? delete p, p = nullptr, void(1) : void(0)

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

void solve_case(int Case) {
  logd(Case);
  int n;
  std::cin >> n;
  std::string s;
  std::cin >> s;
  std::vector<int> p(n);
  for (int i = 0; i < n; ++i) {
    std::cin >> p[i];
    --p[i];
  }

  int64_t ans = 1;
  std::vector<int> v(n, 0);
  for (int i = 0; i < n; ++i) {
    if (v[i] == 1)
      continue;

    std::vector<int> a;
    int j = i;
    while (!v[j]) {
      a.push_back(j);
      v[j] = 1;
      j = p[j];
    }
    logd(a);

    int64_t c = 0;
    std::string t = s;
    do {
      ++c;
      std::string temp = t;
      for (int j : a) {
        t[j] = temp[p[j]];
      }
    } while (t != s);

    ans = std::lcm(ans, c);
  }

  std::cout << ans << "\n";
}

G. Count the Trains

题意

给定一个长度为\(n\)的数组\(a\),还有\(m\)次操作\((x_i, d_i)\),每次令\(a_{x_i} = a_{x_i} - d_i\)。

要求每次操作过后输出\(a\)的前缀最小值数组中有多少个不同的值。

其中\(1 \le n, m \le {10}^5, 0 \le a_i \le {10}^9\)。

思路

记\(a\)的前缀最小值数组为\(s\),易得\(s\)单调非增。

维护一个数组\(w\),如果\(s_x\)是连续相同元素中的第一个,则\(w_x = 1\),否则\(w_x = 0\)。易得\(w\)的元素和即为答案。

\(a_x\)修改之后,如果\(a_x < s_x\),且\(r\)等于\(s\)中满足\(a_i \ge a_x\)的最大的\(i\),那么\(s_x \dots s_r\)都需要更新成\(a_x\),\(w_x\)需要更新成\(1\),\(w_{x+1} \dots w_r\)需要更新成\(0\)。

涉及的操作如区间置数等都是线段树基本操作。\(r\)的话稍微复杂一点点,线段树结合二分或者直接线段树上二分就能求。

然后就是\(s\)和\(w\)分别用线段树维护,然后模拟一下就可以了。

AC代码
// Problem: G. Count the Trains
// Contest: Codeforces - Codeforces Round #797 (Div. 3)
// URL: https://codeforces.com/contest/1690/problem/G
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#define freep(p) p ? delete p, p = nullptr, void(1) : void(0)

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

const int N = 1e5 + 5;
int n, m, a[N], s[N];
namespace S {
int mi[N << 2], tag[N << 2];
void push_up(int x) {
  mi[x] = std::min(mi[x << 1], mi[x << 1 | 1]);
}
void change(int x, int v) {
  mi[x] = tag[x] = v;
}
void push_down(int x) {
  if (tag[x] != INT_MAX) {
    change(x << 1, tag[x]);
    change(x << 1 | 1, tag[x]);
    tag[x] = INT_MAX;
  }
}
void build(int x, int l, int r) {
  tag[x] = INT_MAX;
  if (l == r) {
    mi[x] = s[l];
    return;
  }
  int mid = (l + r) >> 1;
  build(x << 1, l, mid);
  build(x << 1 | 1, mid + 1, r);
  push_up(x);
}
void set(int x, int l, int r, int L, int R, int v) {
  if (l == L && r == R) {
    change(x, v);
    return;
  }
  push_down(x);
  int mid = (l + r) >> 1;
  if (R <= mid)
    set(x << 1, l, mid, L, R, v);
  else if (L > mid)
    set(x << 1 | 1, mid + 1, r, L, R, v);
  else {
    set(x << 1, l, mid, L, mid, v);
    set(x << 1 | 1, mid + 1, r, mid + 1, R, v);
  }
  push_up(x);
}
int query(int x, int l, int r, int L, int R) {
  if (l == L && r == R) {
    return mi[x];
  }
  push_down(x);
  int mid = (l + r) >> 1;
  if (R <= mid)
    return query(x << 1, l, mid, L, R);
  else if (L > mid)
    return query(x << 1 | 1, mid + 1, r, L, R);
  else
    return std::min(query(x << 1, l, mid, L, mid), query(x << 1 | 1, mid + 1, r, mid + 1, R));
}
int getLast(int v) {
  int l = 1, r = n, mid, k = n;
  while (l <= r) {
    mid = (l + r) >> 1;
    if (query(1, 1, n, mid, mid) >= v)
      l = mid + 1, k = mid;
    else
      r = mid - 1;
  }
  return k;
}
}  // namespace S

namespace W {
int sum[N << 2], tag[N << 2];
void push_up(int x) {
  sum[x] = sum[x << 1] + sum[x << 1 | 1];
}
void change(int x, int l, int r, int v) {
  sum[x] = (r - l + 1) * v;
  tag[x] = v;
}
void push_down(int x, int l, int r) {
  if (tag[x] != INT_MAX) {
    int mid = (l + r) >> 1;
    change(x << 1, l, mid, tag[x]);
    change(x << 1 | 1, mid + 1, r, tag[x]);
    tag[x] = INT_MAX;
  }
}
void build(int x, int l, int r) {
  tag[x] = INT_MAX;
  if (l == r) {
    sum[x] = 0;
    return;
  }
  int mid = (l + r) >> 1;
  build(x << 1, l, mid);
  build(x << 1 | 1, mid + 1, r);
  push_up(x);
}
void set(int x, int l, int r, int L, int R, int v) {
  if (l == L && r == R) {
    change(x, l, r, v);
    return;
  }
  push_down(x, l, r);
  int mid = (l + r) >> 1;
  if (R <= mid)
    set(x << 1, l, mid, L, R, v);
  else if (L > mid)
    set(x << 1 | 1, mid + 1, r, L, R, v);
  else {
    set(x << 1, l, mid, L, mid, v);
    set(x << 1 | 1, mid + 1, r, mid + 1, R, v);
  }
  push_up(x);
}
}  // namespace W

void solve_case(int Case) {
  std::cin >> n >> m;

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

  s[1] = a[1];
  for (int i = 2; i <= n; ++i) {
    if (a[i] < s[i - 1]) {
      s[i] = a[i];
    } else {
      s[i] = s[i - 1];
    }
  }

  S::build(1, 1, n);
  W::build(1, 1, n);
  W::set(1, 1, n, 1, 1, 1);
  for (int i = 2; i <= n; ++i) {
    if (s[i] != s[i - 1]) {
      W::set(1, 1, n, i, i, 1);
    }
  }

  for (int _ = 1; _ <= m; ++_) {
    int x, y;
    std::cin >> x >> y;
    a[x] -= y;
    logd(x, y);

    int z = S::query(1, 1, n, x, x);
    if (a[x] < z) {
      int l = x, r = S::getLast(a[x]);
      S::set(1, 1, n, l, r, a[x]);
      W::set(1, 1, n, l, l, 1);
      if (l + 1 <= r)
        W::set(1, 1, n, l + 1, r, 0);
    }

    std::cout << W::sum[1] << " ";
  }
  std::cout << "\n";
}

标签:797,std,le,int,void,mid,Codeforces,Div,define
来源: https://www.cnblogs.com/zengzk/p/16354055.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有