0%

CF1989D Smithing Skill

传送门

Solution

注意到每把武器只使用一种金属锻造,可以独立计算每种金属锭的贡献。

把问题转换为:有一个数 xxnn 个操作,每个操作包含两个参数 aia_ibib_i。当满足 xaix\le a_i,则可执行操作 ii,使 xx 变为 x(aibi)x-(a_i-b_i)。求可对 xx 操作次数的最大值。

不妨设 xi=aibix_i=a_i-b_iyi=aiy_i=a_i。使用 map 筛选这些操作并排序,使其构成具有单调关系的排列,满足 xix_i 严格递增且 yiy_i 严格递减,否则将会出现无用的操作。设 mxm_x 表示筛选出的操作中 xix_i 的最大值。

cuticut_i 表示当 x=ix=i 时,进行一次操作后,xx 最小的减少值。同时遍历操作和 [1,mx][1,m_x],可线性求出此区间内的所有 cuticut_i

sumxsum_x 表示当 x[1,mx]x \in [1,m_x] 时,可对 xx 操作次数的最大值。有递推公式

sumi=sumicuti+1sum_i=sum_{i-cut_i}+1

x>mxx>m_x,则先对 xx 进行若干次 xix_i 最小的操作,使其小于 mxm_x。这部分的操作次数可 Θ(1)\Theta(1) 得出。然后再加上对应的 sumisum_i 值即可。

时间复杂度为 Θ(n+m+mx)\Theta(n+m+m_x)

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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;

ll n, m, a[N], b[N], cut[N], cnt, maxx, num, sum[N], ans;
map<ll, ll> mp;
struct Node {
ll x, y;
} c[N];

int main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++) {
scanf("%lld", &b[i]);
if (!mp[a[i] - b[i]])
mp[a[i] - b[i]] = a[i];
else mp[a[i] - b[i]] = mp[a[i] - b[i]] < a[i] ? mp[a[i] - b[i]] : a[i];
}
c[0].y = 1e9 + 10;
for (auto &t : mp) {
if (t.second >= c[cnt].y) continue;
c[++cnt].x = t.first;
c[cnt].y = t.second;
maxx = max(maxx, c[cnt].y);
}
int p = 1;
for (int i = maxx; i; i--) {
while (p <= cnt && c[p].y > i) ++p;
if (p > cnt) break;
cut[i] = c[p].x;
}
for (int i = 1; i <= maxx; i++)
if (cut[i])
sum[i] = sum[i - cut[i]] + 2;
while (m--) {
scanf("%lld", &num);
if (num <= maxx)
ans += sum[num];
else {
ans += (num - maxx) / c[1].x * 2;
if ((num - maxx) % c[1].x)
ans += 2 + sum[maxx + (num - maxx) % c[1].x - c[1].x];
else
ans += sum[maxx];
}
}
printf("%lld", ans);
return 0;
}