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, "
time:%.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
", 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;
}