Educational Codeforces Round 121 (Rated for Div. 2) ABC(区间求并)
A. Equidistant Letters
直接对原字符串进行排序,这样能保证相同的字母相邻,间隔为0.
#include <iostream>
#include <vector>
#include <algorithm>
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
using namespace std;
int main() {
int t;
cin >> t;
while(t--) {
string s;
cin >> s;
vector<char> v;
for(auto x : s) v.push_back(x);
sort(v.begin(), v.end());
for(auto x : v) cout << x;
cout << endl;
}
return 0;
}
B. Minor Reduction
You are given a decimal representation of an integer 𝑥x without leading zeros.
You have to perform the following reduction on it exactly once: take two neighboring digits in 𝑥x and replace them with their sum without leading zeros (if the sum is 00, it's represented as a single 00).
For example, if 𝑥=10057x=10057, the possible reductions are:
- choose the first and the second digits 11 and 00, replace them with 1+0=11+0=1; the result is 10571057;
- choose the second and the third digits 00 and 00, replace them with 0+0=00+0=0; the result is also 10571057;
- choose the third and the fourth digits 00 and 55, replace them with 0+5=50+5=5; the result is still 10571057;
- choose the fourth and the fifth digits 55 and 77, replace them with 5+7=125+7=12; the result is 1001210012.
What's the largest number that can be obtained?
Input
The first line contains a single integer 𝑡t (1≤𝑡≤1041≤t≤104) — the number of testcases.
Each testcase consists of a single integer 𝑥x (10≤𝑥<1020000010≤x<10200000). 𝑥x doesn't contain leading zeros.
The total length of the decimal representations of 𝑥x over all testcases doesn't exceed 2⋅1052⋅105.
Output
For each testcase, print a single integer — the largest number that can be obtained after the reduction is applied exactly once. The number should not contain leading zeros.
Example
input
Copy
2
10057
90
output
Copy
10012
9
整体逻辑是,首先从高位到低位,如果两个位置交换后比原来大,立即换;如果交换后比原来小但是总位数不变,则记录下最小的这样的位置。遍历后如果已经交换过则直接输出,否则如果有记录下的位置,则交换记录的位置的这两个数并输出。剩余的情况就是不论交换哪个位置必然发生字符串整体缩短,那么交换最高位两个位置即可(因为缩短只可能是两个位置加起来不超过10,这样的话加起来的和比任何一个位置都不小。如果发生缩短,选别的位置最终得到的最高位还是原来的最高位,如果选一开始的两个位置,最终得到的最高位不小于原来的最高位,一定不劣)。
#include <iostream>
#include <stack>
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
using namespace std;
int main() {
int t;
cin >> t;
while(t--) {
string s;
cin >> s;
bool ok = 0;
int pos = -1;
for(int i = 0; i < s.size() - 1; i++) {
int a = s[i] - '0', b = s[i + 1] - '0';
int sum = a + b;
if(a == 0 || b == 0) continue;
if(sum > a * 10 + b) {
a = sum / 10, b = sum % 10;
s[i] = a + '0', s[i + 1] = b + '0';
ok = 1;
break;
} else if(sum >= 10) {
pos = max(pos, i);
}
}
if(ok) cout << s << endl;
else {
if(pos != -1) {
int a = s[pos] - '0', b = s[pos + 1] - '0';
int sum = a + b;
a = sum / 10, b = sum % 10;
s[pos] = a + '0', s[pos + 1] = b + '0';
cout << s << endl;
continue;
}
int n = s.size();
int a = s[0] - '0', b = s[1] - '0';
int sum = a + b;
a = sum / 10, b = sum % 10;
s[0] = a + '0', s[1] = b + '0';
if(!a) s = s.substr(1);
cout << s << endl;
}
}
return 0;
}
C. Monsters And Spells
Monocarp is playing a computer game once again. He is a wizard apprentice, who only knows a single spell. Luckily, this spell can damage the monsters.
The level he's currently on contains 𝑛n monsters. The 𝑖i-th of them appears 𝑘𝑖ki seconds after the start of the level and has ℎ𝑖hi health points. As an additional constraint, ℎ𝑖≤𝑘𝑖hi≤ki for all 1≤𝑖≤𝑛1≤i≤n. All 𝑘𝑖ki are different.
Monocarp can cast the spell at moments which are positive integer amounts of second after the start of the level: 1,2,3,…1,2,3,… The damage of the spell is calculated as follows. If he didn't cast the spell at the previous second, the damage is 11. Otherwise, let the damage at the previous second be 𝑥x. Then he can choose the damage to be either 𝑥+1x+1 or 11. A spell uses mana: casting a spell with damage 𝑥x uses 𝑥xmana. Mana doesn't regenerate.
To kill the 𝑖i-th monster, Monocarp has to cast a spell with damage at least ℎ𝑖hi at the exact moment the monster appears, which is 𝑘𝑖ki.
Note that Monocarp can cast the spell even when there is no monster at the current second.
The mana amount required to cast the spells is the sum of mana usages for all cast spells. Calculate the least amount of mana required for Monocarp to kill all monsters.
It can be shown that it's always possible to kill all monsters under the constraints of the problem.
Input
The first line contains a single integer 𝑡t (1≤𝑡≤1041≤t≤104) — the number of testcases.
The first line of the testcase contains a single integer 𝑛n (1≤𝑛≤1001≤n≤100) — the number of monsters in the level.
The second line of the testcase contains 𝑛n integers 𝑘1<𝑘2<⋯<𝑘𝑛k1<k2<⋯<kn (1≤𝑘𝑖≤1091≤ki≤109) — the number of second from the start the 𝑖i-th monster appears at. All 𝑘𝑖ki are different, 𝑘𝑖ki are provided in the increasing order.
The third line of the testcase contains 𝑛n integers ℎ1,ℎ2,…,ℎ𝑛h1,h2,…,hn (1≤ℎ𝑖≤𝑘𝑖≤1091≤hi≤ki≤109) — the health of the 𝑖i-th monster.
The sum of 𝑛n over all testcases doesn't exceed 104104.
Output
For each testcase, print a single integer — the least amount of mana required for Monocarp to kill all monsters.
Example
input
Copy
3
1
6
4
2
4 5
2 2
3
5 7 9
2 1 2
output
Copy
10
6
7
题意很有迷惑性。这个题实际上是给出一些怪物的出现时间(仅在这一秒出现)以及血量,自己可以选择从某个时间蓄力,下一个时间的蓄力值是当前值+1,一开始蓄力值为0。当然也可以选择打断蓄力,再次蓄力的话蓄力值从1开始。同时可以选择进行攻击,攻击伤害即为蓄力值,且攻击并不消耗蓄力值。每一秒需要消耗当前蓄力值大小的mana,问最终击败所有的怪最小需要多少mana。
首先注意,因为怪仅在那一秒出现,所以在那一秒的蓄力值必须大于等于怪的血量。设第i个怪的出现时间为k[i],血量为h[i],则至少需要从k[i] - h[i] + 1开始蓄力。同时,如果有怪的出现时间比k[i]早,最早蓄力时间比k[i] - h[i] + 1晚,那么这个怪对于答案的贡献是可以忽略的。如果两个怪的蓄力时间短有交叉,那么需要把这两个怪合并(即从前一个怪开始蓄力的时间一直蓄力到后一个怪的出现时间)。这样整个问题就转化成了区间求并了,可以用一个栈维护,轻松解决~
#include <iostream>
#include <stack>
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
using namespace std;
int n;
ll ans;
ll k[105], h[105], lft[105];
ll calc(ll a, ll b) {
return (1 + b - a + 1) * (b - a + 1) / 2;
}
int main() {
int t;
cin >> t;
while(t--) {
cin >> n;
ans = 0;
for(int i = 1; i <= n; i++) cin >> k[i];
for(int i = 1; i <= n; i++) cin >> h[i];
stack<pii> stk;
ll ans = 0;
for(int i = 1; i <= n; i++) {
lft[i] = k[i] - h[i] + 1;
pii tmp = make_pair(lft[i], k[i]);
if(stk.size() && k[i] <= stk.top().second) continue;//被栈顶包含,对答案没有贡献
if(stk.size() && lft[i] > stk.top().second) {//和栈中元素没有交集 直接入栈
stk.push(tmp);
continue;
}
while(stk.size() && stk.top().fi >= lft[i]) stk.pop();//栈中元素被包含
if(stk.size()) {
if(stk.top().se >= tmp.fi) {//有交集
tmp.fi = stk.top().fi;
stk.pop();
}
stk.push(tmp);
} else stk.push(tmp);
}
while(stk.size()) {//计算答案
ans += calc(1ll * stk.top().fi, 1ll * stk.top().se);
stk.pop();
}
cout << ans << endl;
}
return 0;
}
// 1
// 3
// 1 2 3
// 1 1 3
// 1
// 3
// 5 7 9
// 2 1 2
// 1
// 5
// 1 2 3 4 5
// 1 1 1 1 5
// 1
// 3
// 1 2 3
// 1 1 2