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