1. 程式人生 > >Codeforces Round #529 (Div. 3)題解

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;
}