Desciption
给出 个任务,每个任务需要花费
,一开始有
个资源,可以最多为它分配
个,总共可以多分配
个,最后总的花费是
。
Solution
补题的时候发现网上没人写题解,还是写一写希望能帮到和我一样的小白。
显然 是经典的数论分块,对于每个
最多有
种取值,这个可以预处理出来。
随后不妨令 表示前
个花费了多少额外资源的最小花费,于是可以
从上一个位置转移过来,总体时间复杂度
。
关于数论分块的一些思考:
Code
/*
* @Author: Kurisu
*/
#include<bits/stdc++.h>
const int mod = 998244353;
const int N = 1e4 + 5;
#define int long long
int dp[105][10005], a[N], t[N];
std::vector<int> G[105];
int cal(int x, int y) {
return (x + y - 1) / y;
}
void solve() {
int n, m; std::cin >> n >> m;
int ans = 0;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
ans += a[i];
G[i].clear();
for (int l = 1, r = 0; l <= a[i]; l = r + 1) {
int tmp = cal(a[i], l); // make block
if (tmp == 1) {
r = a[i];
} else {
r = (a[i] - 1) / (tmp - 1);
}
G[i].emplace_back(l);
}
}
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) {
std::cin >> t[i];
}
for (int i = 1; i <= std::min(m + 1, t[1]); i++) {
dp[1][i - 1] = cal(a[1], i);
}
for (int i = 2; i <= n; i++) { // make dp
for (int k = 0; k <= t[i] - 1; k++) {
dp[i][k] = dp[i - 1][k] + a[i];
}
for (int j = 0; j < (int)G[i].size(); j++) {
int x = G[i][j], need = x - 1;
if (x > t[i]) { // out of range
break;
}
for (int k = 0; k <= m - need; k++) { // k + need <= m
dp[i][k + need] = std::min(dp[i][k + need], dp[i - 1][k] + cal(a[i], x));
}
}
}
for (int i = 0; i <= m; i++) {
ans = std::min(ans, dp[n][i]);
}
std::cout << ans << '\n';
}
signed main() {
std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
int T = 1; std::cin >> T;
while (T--) {
solve();
}
return 0;
} 
京公网安备 11010502036488号