Atcoder Beginner Contest 369
Atcoder Beginner Contest 369
C-Count Arithmetic Subarrays
题意
给出一个长度为
思路
对于递增的右端点,左端点不减。
使用双指针,枚举右端点,扫描左端点。
时间复杂度:
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 5;
int a[N], n;
ll ans;
void solve() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1, j = 1; i <= n; i ++) {
j = max(j, i);
while (i < n && j < n && a[j + 1] - a[j] == a[i + 1] - a[i]) j ++;
ans += j - i + 1;
}
cout << ans << "\n";
}
int main() {
int T = 1;
// cin >> T;
while (T --)
solve();
return 0;
}
D-Bonus EXP
题意
给出一个长度为
- 将得分增加
,若这是第偶数次执行这个操作,将得分额外增加 。 - 什么也不做。
求最大得分。
思路
定义
初始状态
时间复杂度:
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 5;
int n, a[N];
ll dp[N][2];
void solve() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
memset(dp, -0x3f, sizeof(dp));
dp[0][0] = 0;
for (int i = 1; i <= n; i ++) {
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + a[i]);
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + 2 * a[i]);
}
cout << max(dp[n][0], dp[n][1]) << "\n";
}
int main() {
int T = 1;
// cin >> T;
while (T --)
solve();
return 0;
}
E-Sightseeing Tour
题意
给定一张
每次查询给出
思路
先用 Floyd 求出全源最短路,再枚举给出的边的排列,即经过顺序。
搜索从每条边的哪个点进入,在两条边的端点之间走最短路,并加上该边权。
时间复杂度:
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 405, M = 2e5 + 5;
int n, m, q, K, id[N];
ll f[N][N], ans;
int u[M], v[M], w[M];
void dfs(int p, int x, ll cost) {
if (cost > ans) return ;
if (x == u[id[p]]) x = v[id[p]];
else x = u[id[p]];
cost += w[id[p]];
if (p == K) {
cost += f[x][n];
ans = min(ans, cost);
return ;
}
dfs(p + 1, u[id[p + 1]], cost + f[x][u[id[p + 1]]]);
dfs(p + 1, v[id[p + 1]], cost + f[x][v[id[p + 1]]]);
}
void solve() {
cin >> n >> m;
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= m; i ++) {
cin >> u[i] >> v[i] >> w[i];
f[u[i]][v[i]] = min(f[u[i]][v[i]], 1ll * w[i]);
f[v[i]][u[i]] = min(f[v[i]][u[i]], 1ll * w[i]);
}
for (int i = 1; i <= n; i ++) f[i][i] = 0;
for (int k = 1; k <= n; k ++) {
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
cin >> q;
for (int i = 1; i <= q; i ++) {
cin >> K;
for (int j = 1; j <= K; j ++) cin >> id[j];
sort(id + 1, id + K + 1);
ans = 1e18;
do {
dfs(1, u[id[1]], f[1][u[id[1]]]);
dfs(1, v[id[1]], f[1][v[id[1]]]);
} while(next_permutation(id + 1, id + K + 1));
cout << ans << "\n";
}
}
int main() {
int T = 1;
// cin >> T;
while (T --)
solve();
return 0;
}
F-Gather Coins
题意
给定一个
只能向右和向下走,求从
思路
考虑对金币动态规划,每个金币
暴力转移时间复杂度
发现转移限制为二维偏序,可先把
路径可记录一个
坑点:排序时不能只排
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define ll long long
const int N = 2e5 + 5;
int h, w, n;
struct P {int x, y;};
struct segt {
struct node {
int l, r, mx, MX;
} t[N << 2];
#define ls (p << 1)
#define rs (p << 1 | 1)
friend node operator + (node a, node b) {
node res; res.l = a.l, res.r = b.r;
if (a.mx > b.mx) res.mx = a.mx, res.MX = a.MX;
else res.mx = b.mx, res.MX = b.MX;
return res;
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if (l == r) return;
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}
void modify(int p, int id, int v, int val) {
if (t[p].l == t[p].r) {
t[p].mx = max(t[p].mx, v);
if (t[p].mx == v) t[p].MX = val;
return ;
}
if (id <= t[ls].r) modify(ls, id, v, val);
else modify(rs, id, v, val);
t[p] = t[ls] + t[rs];
}
node query(int p, int l, int r) {
if (l <= t[p].l && t[p].r <= r) return t[p];
node res; res.l = -1;
if (t[ls].r >= l) res = query(ls, l, r);
if (t[rs].l <= r) {
if (res.l == -1) res = query(rs, l, r);
else res = res + query(rs, l, r);
}
return res;
}
} T;
P a[N];
bool cmp(P A, P B) {
if (A.x == B.x) return A.y < B.y;
return A.x < B.x;
}
int dp[N], pre[N], ans, lst;
vector <int> path;
string ANS[N];
void solve() {
cin >> h >> w >> n;
for (int i = 1; i <= n; i ++) cin >> a[i].x >> a[i].y;
a[0].x = 1, a[0].y = 1;
a[n + 1].x = h, a[n + 1].y = w;
sort(a + 1, a + n + 1, cmp);
T.build(1, 1, max(h, w));
T.modify(1, a[1].y, 1, 1);
pre[1] = 0, dp[1] = 1, ans = 1, lst = 1;
for (int i = 2; i <= n; i ++) {
segt::node res = T.query(1, 1, a[i].y);
dp[i] = dp[res.MX] + 1;
pre[i] = res.MX;
if (dp[i] > ans) {
ans = dp[i];
lst = i;
}
T.modify(1, a[i].y, dp[i], i);
}
pre[n + 1] = lst;
int now = n + 1, tot = 0;
while (now) {
lst = pre[now], tot ++;
for (int i = 1; i <= a[now].x - a[lst].x; i ++) ANS[tot] += 'D';
for (int i = 1; i <= a[now].y - a[lst].y; i ++) ANS[tot] += 'R';
now = pre[now];
}
cout << ans << "\n";
for (int i = tot; i >= 1; i --)
cout << ANS[i];
cout << "\n";
}
signed main() {
int T = 1;
// cin >> T;
while (T --)
solve();
return 0;
}
G-As far as possible
题意
在树上选
思路
把树长链剖分,每条边只在一条重链上,不会重复。
选择前
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int n, son[N];
vector <pair <int,int>> e[N];
vector <int> d;
int dis[N];
bool vis[N];
void dfs(int x, int fa, int A) {
for (auto v : e[x]) {
if (v.first == fa) continue;
dfs(v.first, x, v.second);
if (dis[v.first] > dis[son[x]])
son[x] = v.first;
}
dis[x] = dis[son[x]] + A;
}
signed main() {
cin >> n;
for (int i = 1, u, v, w; i < n; i ++) {
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
dfs(1, 0, 0);
for (int i = 1; i <= n; i ++)
vis[son[i]] = 1;
for (int i = 1; i <= n; i ++)
if (!vis[i])
d.push_back(dis[i]);
sort(d.begin(), d.end(), greater<int>());
int ans = 0;
for (int i = 0; i < n; i ++) {
if (i < d.size()) ans += d[i];
cout << ans * 2ll << "\n";
}
return 0;
}
本文来自博客园,作者:maniubi,转载请注明原文链接:https://www.cnblogs.com/maniubi/p/18390995,orz
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效