P11677 [USACO25JAN] Shock Wave P 题解

Description

Bessie 正在试验一种能够产生巨大冲击波的强大的蹄部植入物。她有 NN2N1052 \leq N \leq 10^5)块砖块排开在面前,分别需要至少 p0,p1,,pN1p_0,p_1,\dots,p_{N-1} 的力量才能击破(0pi10180 \leq p_i \leq 10^{18})。

Bessie 可以通过击打特定的砖块来施加力量,但由于她的植入物的奇特性质,它不会对她所击打的那块砖块施加任何力量。相反,如果她选择击打砖块 xx 一次,其中 xx 是一个 [0,N1][0,N-1] 范围内的整数,对所有在 [0,N1][0,N-1] 范围内的整数 ii,它将对砖块 ii 施加 ix|i-x| 的力量。同时这个力量是累积的,因此对一块砖块施加两次 22 的力量将对该砖块施加总共 44 的力量。

请求出击破所有砖块所需要的最少击打次数。

N5×105\sum N\leq 5\times 10^5

Solution

首先观察到 11nn 放到一起是很强的,所以如果存在两次操作分别在 2xyn12\leq x\leq y\leq n-1,则让其分别变为 x1x-1y+1y+1 一定更优。

所以最优方案一定满足只操作 11nn,或者操作 11nn,并在中间某个位置 kk 操作一次。

不妨设 11 操作了 xx 次,nn 操作了 yy 次,并枚举中间的操作位置 kk

则需要满足 i[1,n],x(i1)+y(ni)+ikpi\forall i\in[1,n],x\cdot(i-1)+y\cdot(n-i)+|i-k|\geq p_i

考虑枚举 s=x+ys=x+y,则可以得到不等式:(i1)x+(ni)(sx)piik(i-1)x+(n-i)(s-x)\geq p_i-|i-k|,所以 (2in1)xpiik(ni)s(2i-n-1)x\geq p_i-|i-k|-(n-i)s

只要解出这 nn 个不等式解的交即可,暴力做是 O(n2logV)O(n^2\log V)

注意到在 kk 移动的过程中,第 ii 个方程对应的解只会变化 O(n2in1)O\left(\frac{n}{2i-n-1}\right) 次,这是个调和级数的式子,所以总变化量为 O(nlogn)O(n\log n),求出这些变化点并更新即可做到 O(nlognlogV)O(n\log n\log V)

还是过不了。

考虑先求出中间位置没有操作的答案 resres,这部分可做到 O(nlogV)O(n\log V)。由于一次 11 操作一次 nn 操作一定优于一次中间操作,所以中间操作得到的答案最小为 res1res-1,只 check 这一个答案即可。

时间复杂度:O(nlogV)O(n\log V)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <bits/stdc++.h>

#define int int64_t

using i128 = __int128_t;

const int kMaxN = 1e5 + 5;

int n;
int a[kMaxN], d[kMaxN];
i128 b[kMaxN];

i128 cei(i128 x, int d) {
if (d < 0) x = -x, d = -d;
if (x >= 0) return (x + d - 1) / d;
else return x / d;
}

i128 flr(i128 x, int d) {
if (d < 0) x = -x, d = -d;
if (x >= 0) return x / d;
else return (x - d + 1) / d;
}

struct SGT1 {
int N; i128 mx[kMaxN * 4];
void pushup(int x) {
mx[x] = std::max(mx[x << 1], mx[x << 1 | 1]);
}
void build(int n) {
for (N = 1; N <= n + 1; N <<= 1) {}
std::fill_n(mx, 2 * N, -2e18);
for (int i = 1; i <= n; ++i) {
if (d[i] > 0) mx[i + N] = cei(b[i] - (i - 1), d[i]);
}
for (int i = N - 1; i; --i) pushup(i);
}
void update(int x, i128 v) {
mx[x += N] = v;
for (x >>= 1; x; x >>= 1) pushup(x);
}
i128 query() { return mx[1]; }
} sgt1;

struct SGT2 {
int N; i128 mi[kMaxN * 4];
void pushup(int x) {
mi[x] = std::min(mi[x << 1], mi[x << 1 | 1]);
}
void build(int n) {
for (N = 1; N <= n + 1; N <<= 1) {}
std::fill_n(mi, 2 * N, 2e18);
for (int i = 1; i <= n; ++i) {
if (d[i] < 0) mi[i + N] = flr(b[i] - (i - 1), d[i]);
}
for (int i = N - 1; i; --i) pushup(i);
}
void update(int x, i128 v) {
mi[x += N] = v;
for (x >>= 1; x; x >>= 1) pushup(x);
}
i128 query() { return mi[1]; }
} sgt2;

bool check1(int s) {
i128 L = 0, R = s;
for (int i = 1; i <= n; ++i) {
b[i] = a[i] - (i128)(n - i) * s;
int d = 2 * i - n - 1;
if (d == 0) {
if (b[i] > 0) R = -1;
} else if (d > 0) {
L = std::max(L, cei(b[i], d));
} else {
R = std::min(R, flr(b[i], d));
}
}
return L <= R;
}

bool check2(int s) {
static std::vector<int> vec[kMaxN];
for (int i = 1; i <= n; ++i) vec[i].clear();
for (int i = 1; i <= n; ++i) {
b[i] = a[i] - (i128)(n - i) * s;
d[i] = 2 * i - n - 1;
if (d[i] > 0) {
i128 mi, r = b[i] - flr(b[i], d[i]) * d[i];
if (r >= 1) mi = r - 1;
else mi = d[i] - 1;
for (int j = mi; j <= n; j += d[i]) {
if (i - j >= 1) vec[i - j].emplace_back(i);
if (i + j <= n) vec[i + j].emplace_back(i);
if (i - j - 1 >= 1) vec[i - j - 1].emplace_back(i);
if (i + j + 1 <= n) vec[i + j + 1].emplace_back(i);
}
} else if (d[i] < 0) {
int mi, r = -b[i] - flr(-b[i], -d[i]) * (-d[i]);
mi = (-d[i] - r) % (-d[i]);
for (int j = mi; j <= n; j -= d[i]) {
if (i - j >= 1) vec[i - j].emplace_back(i);
if (i + j <= n) vec[i + j].emplace_back(i);
if (i - j + 1 >= 1) vec[i - j + 1].emplace_back(i);
if (i + j - 1 <= n) vec[i + j - 1].emplace_back(i);
}
}
}
sgt1.build(n), sgt2.build(n);
for (int i = 1; i <= n; ++i) {
for (auto x : vec[i]) {
if (d[x] > 0) sgt1.update(x, cei(b[x] - abs(x - i), d[x]));
else sgt2.update(x, flr(b[x] - abs(x - i), d[x]));
}
i128 L = sgt1.query(), R = std::min<i128>(s, sgt2.query());
if (n % 2 == 1) {
int mid = (n + 1) / 2;
if (d[mid] == 0 && b[mid] - llabs(mid - i) > 0) R = -1;
}
if (L <= R) return 1;
}
return 0;
}

void dickdreamer() {
std::cin >> n;
for (int i = 1; i <= n; ++i) std::cin >> a[i];
int mx = *std::max_element(a + 1, a + 1 + n);
if (!mx) return void(std::cout << "0\n");
int L = -1, R = 2 * mx, res = 2 * mx;
while (L + 1 < R) {
int mid = (L + R) >> 1;
if (check1(mid)) R = res = mid;
else L = mid;
}
if (res >= 2 && check2(res - 2)) --res;
std::cout << res << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

P11677 [USACO25JAN] Shock Wave P 题解
https://sobaliuziao.github.io/2025/03/19/post/ce4b28ff.html
作者
Egg_laying_master
发布于
2025年3月19日
许可协议