C. Palindromic in Both Bases
枚举前一半的数位
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
bool isPalindrome(ll x, int a) {
string s;
while (x) {
s +='0'+x%a;
x /= a;
}
string rs = s;
ranges::reverse(rs);
return s == rs;
}
int main() {
int a; ll n;
cin >> a >> n;
ll ans = 0;
auto check = [&](string s) {
ll y = stoll(s);
if (y <= n and isPalindrome(y, a)) ans += y;
};
for (ll x = 1; x < 1e6; ++x) {
string s = to_string(x);
string rs = s;
ranges::reverse(rs);
s += rs;
check(s);
s.erase(s.begin()+(s.size()/2));
check(s);
}
cout << ans << '\n';
return 0;
}
D. Transmission Mission
先将坐标排序
与其直接考虑“放置 \(M\) 个基站”,不如将其转化为“设置 \(M\) 个区间”,这样更容易理解
具体操作:
- 把问题看作在坐标 \(X_1\) 和 \(X_2\) 之间、\(X_2\) 和 \(X_3\) 之间,\(\cdots\) 等位置划分区间
- 需要选择 \(M-1\) 个间隔不包含任何基站,这样剩下的部分自然构成 \(M\) 个区间
代码实现
#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, m;
cin >> n >> m;
vector<ll> x(n);
rep(i, n) cin >> x[i];
ranges::sort(x);
vector<ll> d;
rep(i, n-1) d.push_back(x[i+1]-x[i]);
ranges::sort(d);
rep(i, m-1) d.pop_back();
ll ans = 0;
for (ll nd : d) ans += nd;
cout << ans << '\n';
return 0;
}
E. Count A%B=C
不难发现满足条件的三元组一定满足 \(a > b > c\)
这样就简单了
答案就是 \(\frac{N(N+1)}{2} - \sum\limits_{b} \lfloor\dfrac{N}{b}\rfloor\)
右边的这个式子就是整除分块的板子题
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using mint = modint998244353;
int main() {
ll n;
cin >> n;
mint ans = mint(n+1)*n/2;
for (ll b = 1; b <= n;) {
ll y = n/b;
ll nb = n/y+1;
ans -= mint(nb-b)*y;
b = nb;
}
cout << ans.val() << '\n';
return 0;
}
F. Jump Traveling
记 dp[v][pre][k] 表示当前位于点 \(k\),上一个访问的点是 \(pre\),已经进行了 \(k\) 次操作
状态数为 \(O(NK)\),转移数为 \(O(N)\),总复杂度为 \(O(N^2K)\),显然超时
注意到,从状态 dp[v][pre][k] 进行转移时,唯一不可访问的点是 pre,因此:
- 只需从
dp[v][pre][k]进行一次有效转移 - 无需重复其他
dp[v][*][k]对同一 \(v\) 和 \(k\) 的转移
实现方法:
- 记录点 \(v\) 已完成的扩散次数
- 通过智能跳过冗余计算,将总复杂度降至 \(O(NK)\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
void solve() {
int n, k;
cin >> n >> k;
vector<P> es;
vector<vector<P>> g(n);
rep(i, n-1) {
int a, b;
cin >> a >> b;
--a; --b;
es.emplace_back(a, b);
g[a].emplace_back(b, i);
g[b].emplace_back(a, n-1+i);
}
const int INF = 1001001001;
vector dist((n-1)*2, vector<int>(k, INF));
vector cnt(n, vector<int>(k));
queue<P> q;
auto push = [&](int ei, int d) {
int w = d%k;
if (dist[ei][w] != INF) return;
dist[ei][w] = d;
q.emplace(ei, d);
};
for (auto [to, ei] : g[0]) push(ei, 1);
while (q.size()) {
auto [ei, d] = q.front(); q.pop();
int v;
{
auto [a, b] = es[ei%(n-1)];
if (ei < n-1) v = b; else v = a;
}
if ((++cnt[v][d%k]) <= 2) {
for (auto [to, ej] : g[v]) {
if (d%k != 0 and ei%(n-1) == ej%(n-1)) continue;
push(ej, d+1);
}
}
}
vector<int> ans(n, INF);
rep(i, (n-1)*2) {
auto [a, b] = es[i%(n-1)];
if (i >= n-1) swap(a, b);
ans[b] = min(ans[b], dist[i][0]);
}
for (int i = 1; i < n; ++i) {
if (ans[i] == INF) ans[i] = -1; else ans[i] /= k;
cout << ans[i] << " \n"[i == n-1];
}
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
G. AtCoder Express 4
线段树优化建图:构建四棵线段树(两棵正向树、两棵反向树),用于高效表示区间关系。
树结构设计:
- 每棵线段树的节点代表一个车站区间。
- 正向树(子节点指向父节点)用于下车操作。
- 反向树(父节点指向子节点)用于上车操作。
- 针对东西方向(左→右和右→左)分别设计两种树结构。
列车连接处理:
- 对于每趟列车,创建虚拟节点。
- 使用线段树将上车区间连接到虚拟节点,再将虚拟节点连接到下车区间。
- 票价计算:基础票价 + 上车车站到上车区间端点的距离 + 下车区间端点到下车车站的距离。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct Node {
int li, ri, lc, rc;
};
int main() {
cin.tie(nullptr) -> sync_with_stdio(false);
int n, m;
cin >> n >> m;
vector<ll> x(n);
rep(i, n) cin >> x[i];
vector<Node> nodes;
rep(i, n) nodes.emplace_back(i, i+1, -1, -1);
vector<vector<pair<int, ll>>> g(n);
vector<int> roots;
// 0: right in
// 1: right out
// 2: left in
// 3: left out
rep(sign, 2) {
rep(dir, 2) {
auto dfs = [&](auto& f, int l, int r) -> int {
if (r-l == 1) return l;
int c = (l+r)/2;
int lc = f(f, l, c);
int rc = f(f, c, r);
int v = nodes.size();
nodes.emplace_back(l, r, lc, rc);
g.push_back({});
ll lcost = 0, rcost = 0;
if (sign == 0) rcost = x[c]-x[l];
else lcost = x[r-1]-x[c-1];
if (dir == 0) {
g[v].emplace_back(lc, lcost);
g[v].emplace_back(rc, rcost);
}
else {
g[lc].emplace_back(v, lcost);
g[rc].emplace_back(v, rcost);
}
return v;
};
roots.push_back(dfs(dfs, 0, n));
}
}
rep(mi, m) {
int sl, sr, tl, tr; ll c;
cin >> sl >> sr >> tl >> tr >> c;
--sl; --tl;
int nv = g.size(); g.push_back({});
auto dfs = [&](auto& f, int type, int l, int r, int v) -> void {
auto [li, ri, lc, rc] = nodes[v];
if (ri <= l or r <= li) return;
if (l <= li and ri <= r) {
ll cost = 0;
if (type&2) cost = x[r-1]-x[ri-1];
else cost = x[li]-x[l];
if (type&1) g[v].emplace_back(nv, cost+c);
else g[nv].emplace_back(v, cost);
return;
}
f(f, type, l, r, lc);
f(f, type, l, r, rc);
};
if (sr <= tl) {
c += x[tl]-x[sr-1];
dfs(dfs, 3, sl, sr, roots[3]);
dfs(dfs, 0, tl, tr, roots[0]);
}
else {
c += x[sl]-x[tr-1];
dfs(dfs, 1, sl, sr, roots[1]);
dfs(dfs, 2, tl, tr, roots[2]);
}
}
const ll INF = 1e18;
int vs = g.size();
vector<ll> dist(vs, INF);
using P = pair<ll, int>;
priority_queue<P, vector<P>, greater<P>> q;
dist[0] = 0; q.emplace(0, 0);
while (q.size()) {
auto [d, v] = q.top(); q.pop();
if (dist[v] != d) continue;
for (auto [u, c] : g[v]) {
ll nd = d+c;
if (dist[u] <= nd) continue;
dist[u] = nd;
q.emplace(nd, u);
}
}
for (int i = 1; i < n; ++i) {
ll ans = dist[i];
if (ans == INF) ans = -1;
cout << ans << ' ';
}
return 0;
}
浙公网安备 33010602011771号