离线赛 2019.10.31
Posted ameiyo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了离线赛 2019.10.31相关的知识,希望对你有一定的参考价值。
2019.10.30
[ Ameiyo ]
A
挺简单的一道 Dp 。。。看 这个博客 。
B
其实可以用 dijsktra
做这道题,但是每次用来更新的都是自己的次小值。
因为当你走到当前点时,老虎会让你不能走最小值,所以是用次小值更新。
每次也是拿次小值最小的点出来更新。
ll mi[N][2];
struct NODE {
int id;
ll w;
inline int operator < (const NODE &__) const {
return w > __.w;
}
} ;
priority_queue < NODE > Q;
int main() {
memset(mi, 0x3f, sizeof mi);
n = read<int>(), m = read<int>(), q = read<int>();
rep (i, 1, m) {
int x = read<int>() + 1, y = read<int>() + 1, c = read<int>();
Addedge(x, y, c), Addedge(y, x, c);
}
rep (i, 1, q) {
int x = read<int>() + 1;
mi[x][0] = mi[x][1] = 0, Q.push((NODE) { x, 0 });
}
while (!Q.empty()) {
int u = Q.top().id; Q.pop();
if (mk[u]) continue;
mk[u] = true;
for (int i = head[u], v; i; i = edge[i].nex) {
v = edge[i].to;
if (mk[v]) continue;
ll tmp = mi[u][1] + edge[i].cost, flag = false;
rep (d, 0, 1)
(tmp < mi[v][d] && (swap(tmp, mi[v][d]), flag = true));
if (flag) Q.push((NODE) { v, mi[v][1] });
}
}
printf("%lld
", mi[1][1]);
return 0;
}
C
一道比较难想到的统计题。
有两种做法,但是两种做法都是基于暴力的 Dp (这个总要会吧。。),然后枚举所有询问跨越的点,通过对点两边的预处理然后合并。
- 分块,复杂度 $ O((n + q) * sqrt {n * l}) $
其实我觉得这不能叫分块。。。
我们每 $ C $ 个点设置一个点,对于所有的点,我们处理出其左边一部分不选的情况下,左边每个点到他的 Dp 值,右边也一样。这样查询的时候就只用考虑中间有一块合并起来做贡献的情况。
因为 $ l $ 很小,所以每次直接暴力处理就行了。
const ll N = 100005, INF = 1e9;
const ll M = 55;
const int C = 4700;
#define max(a, b) ((a) > (b) ? (a) : (b))
int n, m, k, A[N], S[N], tmp[N], tot;
int fl[M][N], fr[M][N];
struct QUERY {
int bl, l, r, id;
inline int operator < (const QUERY &__) const {
return bl < __.bl;
}
} Query[N];
int cur, Ans[N];
void Solve(int id) {
memset(fl, 0, sizeof fl);
memset(fr, 0, sizeof fr);
rep (i, 0, k + 1) {
dep (j, id - i - k + 1, 1)
fl[i][j] = max(fl[i][j + 1],
fl[i][j + k] + S[j + k - 1] - S[j - 1]);
rep (j, id + i + k - 1, n)
fr[i][j] = max(fr[i][j - 1],
fr[i][j - k] + S[j] - S[j - k]);
}
for ( ; cur <= tot && Query[cur].bl == id; ++cur) {
int l = Query[cur].l, r = Query[cur].r, ans = fl[1][l] + fr[0][r];
rep (x, max(0, l + k - id - 1), min(k, r - id))
ans = max(ans, fl[k - x][l] + fr[x + 1][r]
+ S[id + x] - S[id + x - k]);
Ans[Query[cur].id] = ans;
}
}
int main() {
n = read<int>(), k = read<int>();
rep (i, 1, n) S[i] = S[i - 1] + (A[i] = read<int>());
m = read<int>();
rep (i, 1, m) {
int l = read<int>(), r = read<int>();
if (r - l + 1 <= C) {
rep (i, k, r - l + 1)
tmp[i] = max(tmp[i - 1],
tmp[i - k] + S[i + l - 1] - S[i + l - 1 - k]);
Ans[i] = tmp[r - l + 1];
} else Query[++tot] = (QUERY) { r / C * C, l, r, i };
}
sort(Query + 1, Query + tot + 1);
cur = 1;
rep (i, 1, n / C) Solve(i * C);
rep (i, 1, m) printf("%d
", Ans[i]);
return 0;
}
- 分治,复杂度 $ O(n * log n * k + q * k) $
每次选出来的点是当前区间的 $ mid $ ,其他同上。
const ll N = 100005, INF = 1e9;
const ll M = 55;
#define max(a, b) ((a) > (b) ? (a) : (b))
int n, m, k, A[N], S[N];
struct QUERY { int id, l, r; } ;
vector < QUERY > Que[N << 2];
int Ans[N];
#define ls (p << 1)
#define rs (p << 1 | 1)
void Push(int p, int l, int r, int L, int R, int id) {
if (l == r) return (void) (Que[p].push_back((QUERY) { id, L, R }));
int mid = (l + r) >> 1;
if (R <= mid) Push(ls, l, mid, L, R, id);
else if (L > mid) Push(rs, mid + 1, r, L, R, id);
else Que[p].push_back((QUERY) { id, L, R });
}
int fl[M][N], fr[M][N];
void Solve(int p, int l, int r) {
int mid = (l + r) >> 1, siz = Que[p].size();
if (l != r) Solve(ls, l, mid), Solve(rs, mid + 1, r);
if (!siz) return ;
rep (i, 0, k) {
rep (j, l, r) fl[i][j] = fr[i][j] = 0;
dep (j, mid - i - k + 1, l)
fl[i][j] = max(fl[i][j + 1],
fl[i][j + k] + S[j + k - 1] - S[j - 1]);
rep (j, mid + i + k - 1, r)
fr[i][j] = max(fr[i][j - 1],
fr[i][j - k] + S[j] - S[j - k]);
}
rep (i, 0, siz - 1) {
int id = Que[p][i].id, l = Que[p][i].l, r = Que[p][i].r;
int ans = fl[1][l] + fr[0][r];
rep (x, max(0, l + k - mid - 1), min(k, r - mid))
ans = max(ans, fl[k - x][l] + fr[x + 1][r]
+ S[mid + x] - S[mid + x - k]);
Ans[id] = ans;
}
}
int main() {
n = read<int>(), k = read<int>();
rep (i, 1, n) S[i] = S[i - 1] + (A[i] = read<int>());
m = read<int>();
rep (i, 1, m) {
int l = read<int>(), r = read<int>();
Push(1, 1, n, l, r, i);
}
Solve(1, 1, n);
rep (i, 1, m) printf("%d
", Ans[i]);
return 0;
}
[ in 2019.10.31 ]
以上是关于离线赛 2019.10.31的主要内容,如果未能解决你的问题,请参考以下文章