Codeforces Round #529 (Div. 3)题解

ABCF看到以后立马就会做了,ABC差一点做到都比dreamoon切得快(总罚时比dreamoon少1分钟),主要是我在写C的时候multiset不知道为什么坏掉了。。。改了好长时间,最后换了堆 存起来再reverse输出的。。。DE自闭了好长时间然后发现是傻逼题

A.给一个abbcccddddeeeee这样的字符串 输出abcde

  int n;
  cin >> n;
  string a, ans;
  cin >> a;
  int cnt = 0;
  for (int i = 0; i < a.length(); i += ++cnt) ans += a[i];
  cout << ans;

B.给一个数组,问任意去掉一个元素以后的最小极差

肯定去掉最大或者最小的那个,取个min就行了

  int n;
  in, n;
  if (n <= 2) return puts("0"), 0;
  vector<int>a;
  a.resize(n);
  lop0(i, n) in, a[i];
  sort(all(a));
  out, min(a[n-2] - a[0], a[n-1] - a[1]);

C.给出n,m,问n能否分成m个都是2的整数次幂的数相加

首先两个无解条件 1.popcount(n)>m 无解 2.m>n无解(m个数最小是1)

先把n按二进制位拆出来,不够m个的话,每次拆掉最大的数x,分成两个x/2,用个堆或者multiset啥的搞就行了(我也不知道为啥比赛的时候multiset不能支持重复元素了,然后用堆搞的)

  int x, n;
  cin >> x >> n;
  if (__builtin_popcount(x) > n) return puts("NO"), 0;
  if (n > x) return puts("NO"), 0;
  puts("YES");
  priority_queue<int>ans;
  for (int i = 0; i < 30; ++i) if ((1 << i) & x) ans.push(1 << i);
  while (ans.size() < n) {
    int x = ans.top(); ans.pop();
    ans.push(x >> 1), ans.push(x >> 1);
  }
  vector<int>Ans;
  while (!ans.empty()) Ans.pb(ans.top()), ans.pop();
  reverse(all(Ans));
  for (auto it = Ans.begin(); it != Ans.end(); ++it) out, *it, ' ';  

D.给出一个n个点的有向环和每个点u的出边指向的点v,v的出边指向的点w,(v,w)不一定按照顺序给出

输出一个合法的顺序

考虑有三个点 u,v,w(描述同上)如果v给出的两个点里面有w,那么顺序就是<u,v,w>,否则就是<u,w,v>

pii a[MAXN << 1];
bool vis[MAXN << 1];
int main() {
  int n;
  in, n;
  lop1(i, n) in, a[i].xx, a[i].yy;
  vint ans;
  ans.pb(1);
  vis[1] = 1;
  for (int i = 0; i < n; i += 2) {
    int u = a[ans[i]].xx, v = a[ans[i]].yy;
    if (a[u].xx == v || a[u].yy == v) {
      if (!vis[u]) ans.pb(u);
      if (!vis[v]) ans.pb(v);
    }
    else {
      if (!vis[v]) ans.pb(v);
      if (!vis[u]) ans.pb(u);
    }
    vis[u] = vis[v] = 1;
  }
  for (auto it = ans.begin(); it != ans.end(); ++it) out, *it, ' ';
  return 0;
}

E.给个括号序列,问有多少位置取反后整个序列合法

1.线段树

#define ls (o<<1)
#define rs (o<<1|1)
char s[MAXN];
int lv[MAXN << 1], rv[MAXN << 1], n;
//rv[i] i节点对应区间除掉匹配的括号以外)的个数  lv[i] i节点对应区间除掉匹配的括号以外(的个数

inline void pushup(int o) {
  int m = min(lv[ls], rv[rs]);
  lv[o] = lv[ls] - m + lv[rs];
  rv[o] = rv[rs] - m + rv[ls];
}


inline void build(int o, int l, int r) {
  if (l == r) return (s[l] == '(' ? lv : rv)[o] = 1, void();
  build(ls, l, mid), build(rs, mid + 1, r);
  pushup(o);
  // cerr << l << ' ' << r << ' ' << lv[o] << ' ' << rv[o] << endl;
}
inline void Modify(int o, int l, int r, int x) {
  if (l == r) return void(swap(lv[o], rv[o]));
  x <= mid ? Modify(ls, l, mid, x) : Modify(rs, mid+1, r, x);
  pushup(o);
}

int main() {
#ifdef LOCAL_DEBUG
  // freopen("data.in", "r", stdin), freopen("data.out", "w", stdout);
  Dbg = 1;
#endif
  in, n;
  in, s + 1;
  build(1, 1, n);
  if (lv[1] + rv[1] != 2) return puts("0"), 0;
  int ans = 0;
  lop1(i, n) Modify(1, 1, n, i), ans += !(lv[1] + rv[1]), Modify(1, 1, n, i);
  out, ans;



#ifdef LOCAL_DEBUG
  fprintf(stderr, "\ntime:%.5fms", clock() * 1.0 / CLOCKS_PER_SEC * 1000);
#endif
  return 0;
}

2.线性做法,cf上很多人写的我看不懂。。。xzz聚聚几分钟就写出了一个线性代码,我这等彩笔还能看懂,orz xzz orz yyb(事xzz让我干的)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 7;
char S[1000010];
int pre[1000010], suf[1000010], n;
int main() {
  scanf("%d%s", &n, S + 1);
  for (int i = 1; i <= n; ++i)
    if (pre[i - 1] == -1) pre[i] = -1;
    else if (S[i] == '(') pre[i] = pre[i - 1] + 1;
    else if (pre[i - 1]) pre[i] = pre[i - 1] - 1;
    else pre[i] = -1;
  for (int i = n; i; --i)
    if (suf[i + 1] == -1) suf[i] = -1;
    else if (S[i] == ')') suf[i] = suf[i + 1] + 1;
    else if (suf[i + 1]) suf[i] = suf[i + 1] - 1;
    else suf[i] = -1;
  int ans = 0;
  for (int i = 1; i <= n; ++i) ans += ~pre[i - 1] && ~suf[i + 1] && !((S[i] == '(' ? -1 : 1) + pre[i - 1] - suf[i + 1]); //前面和后面合法 改掉以后数量相等
  printf("%d\n", ans);
  return 0;
}

F.给出一个序列a和m条特殊边,对于一条边,若在m条边中已存在,权值是给出的权值跟a[u]+a[v]取min,否则权值是a[u]+a[v],求最小生成树
m条边以外再push进n条边 <最小的a的位置,i,a[i]+最小的a>
然后kruskal

目睹了一位神仙edge越界1e5然后稳稳地AC了此题 orz

struct Edge {
  int u, v;
  ll w;
  inline bool operator < (const Edge & rhs) const {
    return w < rhs.w;
  }
} E[400005];
int fa[200005], n, m;
ll a[200005];
inline int Find(int x) {
  return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
inline int Min(int x, int y) {
  return a[x] < a[y] ? x : y;
}
int main() {
  in, n, m;
  if (n == 1) return puts("0"), 0;
  a[0] = 1e18;
  lop(i, 1, n) in, a[i];
  int Min = min_element(a+1, a+1+n) - a;
  lop(i, 1, m) in, E[i].u, E[i].v, E[i].w;
  lop(i, 1, n) fa[i] = i, E[++m] = (Edge) {Min, i, a[i] + a[Min]};//Min == i也没关系 因为i到i的边不会影响答案
  sort(E + 1, E + 1 + m);
  int cnt = 0; ll ans = 0;
  lop(i, 1, m) {
    int u = Find(E[i].u), v = Find(E[i].v);
    if (u == v) continue;
    fa[u] = v, ans += E[i].w;
    if (++cnt == n - 1) break;
  }
  out, ans;
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/storz/p/10192675.html