传送门
Solution
注意到每把武器只使用一种金属锻造,可以独立计算每种金属锭的贡献。
把问题转换为:有一个数 x 和 n 个操作,每个操作包含两个参数 ai、bi。当满足 x≤ai,则可执行操作 i,使 x 变为 x−(ai−bi)。求可对 x 操作次数的最大值。
不妨设 xi=ai−bi,yi=ai。使用 map 筛选这些操作并排序,使其构成具有单调关系的排列,满足 xi 严格递增且 yi 严格递减,否则将会出现无用的操作。设 mx 表示筛选出的操作中 xi 的最大值。
设 cuti 表示当 x=i 时,进行一次操作后,x 最小的减少值。同时遍历操作和 [1,mx],可线性求出此区间内的所有 cuti。
设 sumx 表示当 x∈[1,mx] 时,可对 x 操作次数的最大值。有递推公式
sumi=sumi−cuti+1
若 x>mx,则先对 x 进行若干次 xi 最小的操作,使其小于 mx。这部分的操作次数可 Θ(1) 得出。然后再加上对应的 sumi 值即可。
时间复杂度为 Θ(n+m+mx)
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; }
|