A. Strong Password
题目大意
给定一个字符串,字符串的输入时间为:
-
第一个字符输入需2秒;
-
若该字符与上一个输入字符一致,则输入需1秒,否则为2秒
问在字符串中任意插入一个字符后,输入最长时间。
思路
考虑,当破坏字符串连续字符输入可以有效提高时间;如果存在相同连续字符,则插入不同字符破坏,否则在末尾插入与末尾不相同的即可。
代码实现
void solve() {
string s; cin >> s;
int id = -1;
for (int i = 0; i < s.size() - 1; i++) {
if (s[i] == s[i + 1])id = i;
}
for (int i = 0; i < s.size(); i++) {
cout << s[i];
if (i == id) {
if (s[i] == 'a') {
cout << "b";
}
else {
cout << "a";
}
}
}
if(id==-1){
if (s.back() == 'a') {
cout << "b";
}
else {
cout << "a";
}
}
cout << "\n";
}
B. Make Three Regions
题目大意
给定一个两行n列的网格,网格中存在一些墙,保证网格中只存在一个连通区域。
问有多少个可以修改的位置,使得连通块变为三个。
思路
只有两种情况,看代码判断处吧。
代码实现
char dt[4][210000];
void solve() {
ll n; cin >> n;
dt[1][0] = dt[2][0] = dt[1][n + 1] = dt[2][n + 1] = 'x';
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= n; j++) {
cin >> dt[i][j];
}
}
ll ans = 0;
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= n; j++) {
if (dt[i][j] == '.') {
if (i == 1) {
if (dt[2][j] == '.' && dt[2][j - 1] == 'x' && dt[2][j + 1] == 'x' && dt[1][j - 1] == '.' && dt[1][j + 1] == '.') {
ans++;
}
}
else {
if (dt[1][j] == '.' && dt[1][j - 1] == 'x' && dt[1][j + 1] == 'x' && dt[2][j - 1] == '.' && dt[2][j + 1] == '.') {
ans++;
}
}
}
}
}
cout << ans << "\n";
}
C. Even Positions
题目大意
给定一奇数位之上全部消失的括号序列,问如何补充括号序列,使代价最小。
代价计算为,待补充的位置与之匹配位置的长度。
思路
对于括号来说,越近补充越好。
我们从前往后扫一次左括号,从后往前扫一次右括号,计算即可。
代码实现
void solve() {
ll n; cin >> n;
string s; cin >> s;
ll ans = 0;
queue<ll>id;
vector<bool>v(s.size(),false);
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
id.push(i);
}
if (s[i] == '_') {
if (id.size()) {
ll now = id.front(); id.pop();
ans += i - now;
v[i] = true;
v[now] = true;
s[i] = 'x';
}
}
}
while (id.size())id.pop();
for (int i = s.size(); i >= 0; i--) {
if (s[i] == ')') {
id.push(i);
}
if (s[i] == '(' && v[i] == false&&id.size()) {
id.pop();
}
if (s[i] == '_'&&v[i]==false) {
if (id.size()) {
ll now = id.front(); id.pop();
ans += now - i;
s[i] = 'x';
}
}
}
cout << ans << "\n";
}
D. Maximize the Root
题目大意
给定一棵有根树,根节点为1,每个结点均有权值。现在有以下操作,当我们选择一结点加1时,我们要求他的子树上的所有结点均减1。在保证最后树上无负值的情况下,问根节点1的权值最大值为多少。
思路
考虑,对于每个结点来说,如果他比他子结点权值最小值都要大,那么他的最大值为应该为他子树上的最小值与他本身全值得一半;如果他得值要比他的子节点权值最小值还要小,那么不需要不变化。
拓扑排序,从叶节点一直按上述操作推上来,每次当结点弹出得时候,对结点的子节点按权值排序,然后比较最小值更新当前点权值即可。当操作到根节点1的时候,直接将根节点的子节点权值的最小值加上即是可以得到的最大值。
代码实现
ll fa[210000];
ll val[210000];
ll in[210000];
vector<ll>to[210000];
void solve() {
ll n; cin >> n;
for (int i = 1; i <= n; i++) {
cin >> val[i];
in[i] = 0;
to[i].clear();
}
for (int i = 2; i <= n; i++) {
ll F; cin >> F;fa[i] = F;
to[F].push_back(i);
in[i]++;
in[F]++;
}
queue<ll>id;
for (int i = 2; i <= n; i++) {
if (in[i] == 1) {
id.push(i);
in[i]--;
}
}
while (id.size()) {
ll now = id.front(); id.pop();
if (to[now].size()) {
sort(to[now].begin(), to[now].end(), [&](auto a, auto b) {
return val[a] < val[b];
});
ll y = to[now][0];
if (now == 1) {
val[1] += val[y];
break;
}
if (val[y] < val[now]) {
val[now] = val[y];
}
else {
val[now] = (val[y] + val[now]) / 2;
}
}
ll x = fa[now];
in[x]--;
if (x == 1) {
if (in[x] == 0) {
id.push(x);
}
}
else {
if (in[x] == 1) {
id.push(x);
}
}
}
cout << val[1] << "\n";
}