T1:New Scheme
模拟
代码实现
def solve():
s = list(map(int, input().split()))
for i in range(8):
if s[i]%25 != 0:
return False
if s[i] < 100 or s[i] > 675:
return False
for i in range(7):
if s[i] > s[i+1]:
return False
return True
if solve():
print('Yes')
else:
print('No')
T2:Default Price
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<string> c(n), d(m+1);
vector<int> p(m+1);
rep(i, n) cin >> c[i];
rep(i, m) cin >> d[i+1];
rep(i, m+1) cin >> p[i];
map<string, int> mp;
rep(i, m) mp[d[i+1]] = p[i+1];
int ans = 0;
rep(i, n) {
int price = mp[c[i]];
if (price == 0) price = p[0];
ans += price;
}
cout << ans << '\n';
return 0;
}
T3:Standings
对这 \(n\) 个人按 \(\frac{a_i}{a_i+b_i}\) 的大小降序排序,但对于 \(\frac{a_i}{a_i+b_i}\) double
有精度问题,可以考虑转化成整式,即 \(a_i *(a_j+b_j) > a_j*(a_i+b_i)\)
此时发现会 wa
,注意到每个人应该是按下标升序,所以应该做稳定排序
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<int> a(n), b(n);
rep(i, n) cin >> a[i] >> b[i];
rep(i, n) b[i] += a[i];
vector<int> ans(n);
iota(ans.begin(), ans.end(), 0);
stable_sort(ans.begin(), ans.end(), [&](int i, int j) {
return (ll)a[i]*b[j] > (ll)a[j]*b[i];
});
rep(i, n) cout << ans[i]+1 << ' ';
return 0;
}
T4:Snuke Maze
\(\operatorname{bfs}\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};
int main() {
int h, w;
cin >> h >> w;
vector<string> s(h);
rep(i, h) cin >> s[i];
vector<int> mp(256);
string T = "snukes";
rep(i, 5) mp[T[i]] = T[i+1];
vector used(h, vector<bool>(w));
queue<P> q;
used[0][0] = true;
q.emplace(0, 0);
while (q.size()) {
auto [i, j] = q.front(); q.pop();
rep(v, 4) {
int ni = i+di[v], nj = j+dj[v];
if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
if (s[ni][nj] != mp[s[i][j]]) continue;
if (used[ni][nj]) continue;
used[ni][nj] = true;
q.emplace(ni, nj);
}
}
if (used[h-1][w-1]) puts("Yes");
else puts("No");
return 0;
}
T5:MEX
可以考虑枚举中间的 E
,对于两边的 \(M\) 和 \(X\),都对应着三种数 \(0, 1, 2\),于是我们不妨记 \(M_0, M_1, M_2\) 以及 \(X_0, X_1, X_2\),预处理出前缀中 M
对应的 \(M_0, M_1, M_2\) 的个数以及后缀中 X
对应的 \(X_0,X_1,X_2\) 的个数,然后利用乘法原理求出相应的贡献
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<int> a(n);
string s;
rep(i, n) cin >> a[i];
cin >> s;
ll ans = 0;
vector<int> m(3), x(3);
rep(k, n) if (s[k] == 'X') x[a[k]]++;
auto mex = [](int a, int b, int c) {
int s = 1<<a|1<<b|1<<c;
int res = 0;
while (s>>res&1) res++;
return res;
};
rep(j, n) {
if (s[j] == 'E') {
rep(i, 3)rep(k, 3) {
ll now = (ll)m[i]*x[k];
ans += now*mex(i, a[j], k);
}
}
if (s[j] == 'M') m[a[j]]++;
if (s[j] == 'X') x[a[j]]--;
}
cout << ans << '\n';
return 0;
}
也可以用 \(dp\) 来做
记 dp[i][j][k]
表示到第 \(i\) 个数为止最后一个数对应的字符是 MEX
中的第 \(j\) 个且所选择的三个数的集合为 \(k\) 时的方案数
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<int> a(n);
string s;
rep(i, n) cin >> a[i];
cin >> s;
string T = "MEX";
auto mex = [](int k) {
int res = 0;
while (k>>res&1) res++;
return res;
};
vector dp(4, vector<ll>(8));
dp[0][0] = 1;
rep(i, n) {
rep(j, 3) if (s[i] == T[j]) {
rep(k, 8) {
dp[j+1][k|1<<a[i]] += dp[j][k];
}
}
}
ll ans = 0;
rep(k, 8) ans += dp[3][k]*mex(k);
cout << ans << '\n';
return 0;
}
T6:Vouchers
贪心
从折扣金额较大的优惠券开始,在可以使用的范围内,对原价最低的商品用这张优惠券即可!
可以使用 std::multiset
的 lower_bound
函数来解决。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
int main() {
int n, m;
cin >> n >> m;
multiset<int> s;
ll ans = 0;
rep(i, n) {
int p;
cin >> p;
s.insert(p);
ans += p;
}
vector<P> cp(m);
rep(i, m) cin >> cp[i].second;
rep(i, m) cin >> cp[i].first;
sort(cp.rbegin(), cp.rend());
for (auto [d, l] : cp) {
auto it = s.lower_bound(l);
if (it == s.end()) continue;
s.erase(it);
ans -= d;
}
cout << ans << '\n';
return 0;
}
T7:Minimum Xor Pair Query
如何求一个集合中的任意两数的异或的最小值?
\(\mathcal{O}(n\log n)\) 的做法:
- 可以对原集合做升序排序,然后遍历相邻两数的异或值,同时更新最小值就能得到答案
对于原题,我们只需开两个 std::multiset
来维护即可,一个用来维护原数集,一个用来维护相邻两数的异或所构成的集合
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using uint = unsigned;
using P = pair<int, int>;
int main() {
int q;
cin >> q;
multiset<uint> s, t;
// 这里加哨兵的作用了为了避免判空
s.insert(0);
s.insert(1u<<31);
t.insert(1u<<31);
rep(qi, q) {
int type;
cin >> type;
if (type == 3) {
cout << *t.begin() << '\n';
}
else {
uint x;
cin >> x;
x += 1u<<30; // 避免集合中的第一个数成为答案
if (type == 1) {
auto it = s.insert(x);
uint l = *prev(it);
uint r = *next(it);
t.erase(t.find(l^r));
t.insert(l^x);
t.insert(r^x);
}
else {
auto it = s.erase(s.find(x));
int r = *it;
uint l = *prev(it);
t.insert(l^r);
t.erase(t.find(l^x));
t.erase(t.find(r^x));
}
}
}
return 0;
}