校内场-提高组 ZYZSC-S-Round 2
官方题解:付费观看
A 降水(rain)
分析
场切了。
但是,最后一个样例那个样子不是显然的 A t C o d e r AtCoder AtCoder 风格吗?
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n;
int a[N];
int sum;
signed main(){
// freopen("rain.in", "r", stdin);
// freopen("rain.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
int sum0 = 0, sum1 = 0;
for (int i = 1; i <= n; i++){
cin >> a[i];
sum += a[i];
a[i] = a[i] * 2;
if (i % 2 == 0){
sum0 += a[i];
}
else{
sum1 += a[i];
}
}
for (int i = 1; i <= n; i++){
if (i % 2 == 0){
cout << sum0 - sum << " ";
sum0 -= a[i];
sum1 += a[i];
}
else{
cout << sum1 - sum << " ";
sum1 -= a[i];
sum0 += a[i];
}
}
}
B 括号序列(bracket)
原题链接:B 括号序列(bracket)
分析
这个真没盒到原。不过,我大概花了不到一个小时就写出来了吧......就是你观察到只有合法的序列可以进行操作,所以你可以判到 -1 的分。然后,你维护一个每个位置前面 ( 和 ) 的个数,减一下,取个 max \max max,然后拿总长度减去 max × 2 \max\times2 max×2 就行了。因为你 已经保证了序列合法。
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 3000005;
string s;
int n;
bool vis[20];
int pre_up[N], pre_down[N];
int suf_up[N], suf_down[N];
int tot0, tot1;
void init(){
for (int i = 0; i < n; i++){
if (s[i] == '('){
tot0++;
pre_up[i] = pre_up[max(i - 1, 0)] + 1;
pre_down[i] = pre_down[max(i - 1, 0)];
}
if (s[i] == ')'){
tot1++;
pre_up[i] = pre_up[max(i - 1, 0)];
pre_down[i] = pre_down[max(i - 1, 0)] + 1;
}
}
}
bool check1(string t){
stack<int> stk;
for (int i = 0; i < (int)t.length(); i++){
if (t[i] == '('){
stk.push(i);
}
if (t[i] == ')'){
if (stk.empty())
return false;
stk.pop();
}
}
if (stk.empty())
return true;
return false;
}
bool check2(string t){
int m = t.length();
if (!check1(t))
return false;
for (int i = 0, j = m - 1; i <= j; i++, j--){
if (t[i] != '(' || t[j] != ')'){
return false;
}
}
return true;
}
int ans;
void dfs(int p){
if (p == n){
string tmp1 = "", tmp2 = "";
int cnt = 0;
for (int i = 0; i < n; i++){
if (vis[i] == true){ // not keep
tmp1 += s[i];
}
else{ // keep
tmp2 += s[i];
cnt++;
}
}
if (check1(tmp1) && check2(tmp2)){
ans = max(ans, cnt);
}
return ;
}
vis[p] = true;
dfs(p + 1);
vis[p] = false;
dfs(p + 1);
}
signed main(){
freopen("bracket.in", "r", stdin);
freopen("bracket.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> s;
n = s.length();
if (!check1(s)){
cout << -1;
return 0;
}
if (n <= 16){ //(((())(()))(()))
dfs(1);
cout << n - ans;
return 0;
}
// vector<int> up, down;
// for (int i = 0, cnt0 = 0, cnt1 = 0; i < n; i++){
// if (s[i] == '('){
// if (cnt1 != 0){
// down.push_back(cnt1);
// cnt1 = 0;
// }
// cnt0++;
// }
// if (s[i] == ')'){
// if (cnt0 != 0){
// up.push_back(cnt0);
// cnt0 = 0;
// }
// cnt1++;
// }
// }
init();
int mx = 0;
for (int i = 0; i < n; i++){
mx = max(pre_up[i] - pre_down[i], mx);
}
cout << n - mx * 2;
}
打完前两个出去跑操了,因为坐着也没事干,跑了跑步,把后两题的暴力想了一下。
C 树(tree)
原题链接:D. Tree Elimination
分析
*2900 某教练竟然评蓝?还有人类吗?(感觉 lz 要成为 胖头鱼 了😭)
然后,菊花是简单的,不过没有什么启发性。
然后,链的问题在于,我看出来了一个从前面两个转的 DP,然后没有看出来斐波那契数列😭不过击球手上物理课之前提醒我了。感觉之前的代码交上去也有分?不知道。
然后,链给予了我们丰富的思考,我们的 DP 似乎终于有用了。
我还是有一定实力的,因为我看到了这个 DP 状态的一部分,但是在一颗标准的树上,这个还是困难的,少了一些东西。
D 冒泡排序二合一(sort)
原题链接:冒泡排序二合一(sort)
分析
没有盒到原,我也不是很想补,不如去学个分块之类的东西,争取下次序列问题多拿一点。