T1:Yay!
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
string s;
cin >> s;
vector<int> cnt(256);
for (char c : s) cnt[c]++;
char one = '?';
for (char c = 'a'; c <= 'z'; ++c) {
if (cnt[c] == 1) one = c;
}
rep(i, s.size()) {
if (s[i] == one) {
cout << i+1 << '\n';
}
}
return 0;
}
T2:Which is ahead?
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> p(n);
rep(i, n) cin >> p[i];
vector<int> x(n+1);
rep(i, n) x[p[i]] = i;
int q;
cin >> q;
rep(qi, q) {
int a, b;
cin >> a >> b;
if (x[a] < x[b]) cout << a << '\n';
else cout << b << '\n';
}
return 0;
}
T3:Many Replacement
只需记录每种字符最后变成了哪个字符即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, q;
string s;
cin >> n >> s >> q;
string t;
rep(i, 26) t += 'a'+i;
rep(qi, q) {
char c, d;
cin >> c >> d;
rep(i, 26) {
if (t[i] == c) t[i] = d;
}
}
rep(i, n) {
int j = s[i]-'a';
s[i] = t[j];
}
cout << s << '\n';
return 0;
}
T4:Square Pair
可以先将每个数中的最大的平方因子除掉,然后就变成简单的组合计数问题了
代码实现
#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);
rep(i, n) cin >> a[i];
rep(i, n) {
int x = a[i];
for (int j = 2; ; ++j) {
int y = j*j;
if (y > x) break;
while (x%y == 0) x /= y;
}
a[i] = x;
}
ll ans = 0;
int zero = 0;
rep(i, n) {
if (a[i] == 0) {
zero++;
}
}
ans += (ll)zero*(zero-1)/2;
map<int, int> mp;
for (int x : a) {
if (x == 0) continue;
ans += zero;
ans += mp[x];
mp[x]++;
}
cout << ans << '\n';
return 0;
}
T5:Last Train
建反图跑Dijkstra
用大根堆来做堆优化
代码实现
#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<ll, int>;
struct Edge {
int from; ll l, d, k, c;
Edge(int from=-1, ll l=0, ll d=0, ll k=0, ll c=0): from(from), l(l), d(d), k(k), c(c) {}
};
int main() {
int n, m;
cin >> n >> m;
vector<vector<Edge>> g(n);
rep(i, m) {
int l, d, k, c, a, b;
cin >> l >> d >> k >> c >> a >> b;
--a; --b;
g[b].emplace_back(a, l, d, k, c);
}
const ll INF = 2e18;
vector<ll> f(n, -INF);
f[n-1] = INF;
priority_queue<P> q;
q.emplace(INF, n-1);
while (q.size()) {
auto [t, v] = q.top(); q.pop();
if (f[v] != t) continue;
for (auto&& e : g[v]) {
ll nt = t-e.c;
if (e.l > nt) continue;
ll k = (nt-e.l)/e.d;
k = min(k, e.k-1);
ll nf = e.l+e.d*k;
if (f[e.from] >= nf) continue;
f[e.from] = nf;
q.emplace(nf, e.from);
}
}
rep(i, n-1) {
ll ans = f[i];
if (ans == -INF) puts("Unreachable");
else cout << ans << '\n';
}
return 0;
}
T6:Black Jack
注意到庄家的决策是固定的,所以我们可以把 \(y\) 在不同值的分布概率求出来
记 f[i]
表示 \(y = i\) 的概率
你只有在 \(x \leqslant N\) 且 (\(y > N\) 或 \(x > y\)) 的情况下能获胜
\(x \leqslant N\) 这个条件可以不考虑
对于 \(y>N\),它的概率就是 \(\sum\limits_{i = {N+1}}^{L+D-1} f[i]\)
而对于 \(x > y\),不妨令 \(g[i]\) 表示从 \(x = i\) 时掷骰子最后的胜率,从后往前转移
最后的答案就是 \(g[0]\)
可以用前缀和来优化
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, l, d;
cin >> n >> l >> d;
int m = max(n, l+d)+5;
vector<double> dy(m);
{
vector<double> dp(m);
dp[0] = 1;
double s = 0;
for (int i = 1; i < m; ++i) {
s += dp[i-1];
if (i-d-1 >= 0) s -= dp[i-d-1];
// double now = 0;
// for (int j = 1; j <= d; ++j) {
// if (i-j >= 0) now += dp[i-j];
// }
// now /= d;
double now = s/d;
if (i < l) dp[i] = now;
else dy[i] = now;
}
}
n++;
vector<double> win(n);
{
double now = 0;
for (int i = n; i < m; ++i) now += dy[i];
rep(i, n) {
win[i] = now;
now += dy[i];
}
}
double ans = 0;
{
vector<double> dp(n+d+1);
double s = 0;
for (int i = n-1; i >= 0; --i) {
s += dp[i+1];
s -= dp[i+d+1];
// double now = 0;
// for (int j = 1; j <= d; ++j) now += dp[i+j];
// now /= d;
double now = s/d;
dp[i] = max(win[i], now);
}
ans = dp[0];
}
printf("%.10f\n", ans);
return 0;
}
T7:Retroactive Range Chmax
设置节点的数据结构:
- 添加/删除值
- 询问 max
所以可以用 multiset
来实现
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
struct segtree {
int n;
vector<multiset<int>> d;
segtree(int mx=0) {
n = 1;
while (n < mx) n <<= 1;
d.resize(n*2);
}
void add(int l, int r, int x) {
l += n; r += n;
while (l < r) {
if (l%2) d[l].insert(x), l++;
if (r%2) r--, d[r].insert(x);
l >>= 1; r >>= 1;
}
}
void del(int l, int r, int x) {
l += n; r += n;
while (l < r) {
if (l%2) d[l].erase(d[l].find(x)), l++;
if (r%2) r--, d[r].erase(d[r].find(x));
l >>= 1; r >>= 1;
}
}
int get(int i) {
int res = 0;
i += n;
while (i) {
if (d[i].size()) res = max(res, *d[i].rbegin());
i >>= 1;
}
return res;
}
};
int main() {
cin.tie(nullptr) -> sync_with_stdio(false);
int n;
cin >> n;
segtree t(n);
rep(i, n) {
int a;
cin >> a;
t.add(i, i+1, a);
}
int q;
cin >> q;
vector<tuple<int, int, int>> qs(q);
rep(qi, q) {
int type;
cin >> type;
if (type == 1) {
int l, r, x;
cin >> l >> r >> x;
--l;
t.add(l, r, x);
qs[qi] = tie(l, r, x);
}
if (type == 2) {
int i;
cin >> i;
--i;
auto [l, r, x] = qs[i];
t.del(l, r, x);
}
if (type == 3) {
int i;
cin >> i;
--i;
int ans = t.get(i);
cout << ans << '\n';
}
}
return 0;
}