The 3rd Universal Cup. Stage 12: Qinhuangdao
A. Balloon Robot
首先我们可以把时间和坐标都映射为从0 开始的。
然后对于一个事件\((a,b)\),实际上和\((a-1,b-1)\)是等价的。因此我们可以把所有的事件都放到位置\(0\)上发生。
这样做有什么好处?发气球从每秒都可以发变成了,每\(m\)秒发一批。这样我们就可以枚举第一次发气球的时间,并用前缀和快速的计算出其他事件等待的时间。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
const int inf = LLONG_MAX / 2;
void solve() {
int n, m, p;
cin >> n >> m >> p;
vi s(n);
for(auto &i : s)
cin >> i, i --;
map<int,int> cnt;
for(int a, b; p; p --) {
cin >> a >> b, a --;
a = s[a] , b --;
b = (b - a + m) % m;
cnt[b] ++;
}
vi val(1), num(1);
for(auto [x, y] : cnt){
val.push_back(x);
num.push_back(y);
}
int N = val.size() - 1;
vi preVal(N + 1), preNum(N + 1);
for(int i = 1; i <= N; i ++) {
preVal[i] = preVal[i - 1] + val[i] * num[i];
preNum[i] = preNum[i - 1] + num[i];
}
int res = inf;
for(int i = 1 , ret; i <= N; i ++) {
ret = 0;
if(i - 1 >= 1) ret += val[i] * preNum[i - 1] - preVal[i - 1];
if(i + 1 <= N) ret += (val[i] + m) * (preNum[N] - preNum[i]) - (preVal[N] - preVal[i]);
res = min(res, ret);
}
cout << res << "\n";
return;
}
i32 main() {
int T;
cin >> T;
while(T --)
solve();
return 0;
}
C. Crusaders Quest
这个题目数据范围很小直接暴力枚举就好了。
#include <bits/stdc++.h>
using namespace std;
const string tmp = "gao";
void solve() {
string s;
cin >> s;
int res = 0;
auto dfs = [&res](auto &&self, string s, int cnt) -> void {
res = max(res, cnt);
if(s.size() < 3){
return;
}
for(int i = 0, j; i < s.size(); i ++) {
j = i;
while(j < s.size() and s[i] == s[j]) j ++;
string t = s;
t.erase(i, j - i);
self(self, t, cnt + (i + 3 == j));
}
return;
};
dfs(dfs, s, 0);
cout << res << "\n";
return;
}
int main() {
int T;
cin >> T;
while(T --)
solve();
return 0;
}
E. String of CCPC
可以发现,增加两个及以上的字母一定不是最优解。因此至多只会增加一个字母。
考虑增加字母的情况,当且仅当出现CPC
,CCC
,CCP
三种情况。
但是要注意CCC
可能会出现这种情况CCCPC
,此时如果在第二个C
后面增加一个P
,就会变成CCPCPC
,并不会更优,因此要特判去掉这种情况。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
const int inf = LLONG_MAX / 2;
void solve() {
int n;
cin >> n;
string s;
cin >> s;
int res = 0, f = 0;
for(int i = 0; i < n; i ++) {
if(s.substr(i, 4) == "CCPC") {
res ++;
i += 2;
} else if(f == 0) {
if(s.substr(i, 3) == "CPC") {
res ++, f = 1;
} else if(s.substr(i, 3) == "CCP") {
res ++, f = 1;
} else if(s.substr(i, 3) == "CCC" and s.substr(i + 1, 4) != "CCPC") {
res ++, f = 1;
}
}
}
cout << res << "\n";
}
i32 main() {
int T;
cin >> T;
while(T --)
solve();
return 0;
}
G. Numbers
我们可以贪心的放置数字。我们从高位到低位逐位考虑。
对于第\(x\)位,如果第\(x-1\)都放满已经有剩余,也就是\((2^x-1)\times m < n\),则\(x\)就必须要放。如果\(x\)需要放置,则尽可能的放满。
实现需要高精度,可以用 Python 实现。
def log2(x):
ret = 0
while x > 1:
ret += 1
x //= 2
return ret
def solve():
n, m = map(int,input().split(' '))
res = 0
x = 2 ** int(log2(n) + 1)
while n > 0:
if (x - 1) * m < n :
res += x
n -= min(n //x, m) * x
x //= 2
print(res)
T = int(input())
for _ in range(T) :
solve()
L. One-Dimensional Maze
如果从一个点向左走就必须全部L
,如果一个点向右走就全部是R
。计算一下需要修改的个数即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
const int inf = LLONG_MAX / 2;
void solve() {
int n, m;
cin >> n >> m, m --;
string s;
cin >> s;
int res = 0;
for(int i = m; i < n - 1; i ++)
res += (s[i] == 'L');
int ret = 0;
for(int i = m; i > 0; i --)
ret += (s[i] == 'R');
cout << min(res, ret) << "\n";
return;
}
i32 main() {
int T;
cin >> T;
while(T --)
solve();
return 0;
}
M. Safest Buildings
距离圆心距离小于\(|R - 2r|\)的点肯定更优,除此之外离圆心越近的点越优。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const i64 inf = LLONG_MAX / 2;
void solve() {
int n, R, r;
cin >> n >> R >> r;
i64 val = inf, d = (2ll * r - R) * (2ll * r - R);
vector<int> ret, res;
for(int i = 1; i <= n; i ++) {
i64 x, y, dis;
cin >> x >> y;
dis = x * x + y * y;
if(dis < val) {
val = dis, ret = vector<int>(1, i);
} else if(dis == val) {
ret.push_back(i);
}
if(dis <= d) {
res.push_back(i);
}
}
if(not res.empty()) {
cout << res.size() << "\n";
for(auto i : res)
cout << i << " \n"[i == res.back()];
return;
}
cout << ret.size() << "\n";
for(auto i : ret)
cout << i << " \n"[i == ret.back()];
return;
}
int main() {
int T;
cin >> T;
while(T --)
solve();
return 0;
}