P13009题解
传送门:https://www.luogu.com.cn/problem/P13009
考虑向下取整数学意义。不妨令 \(m=k*a[i]+b \ (0 \leq b< a[i])\)
则 \(\lfloor\frac{m}{a[i]}\rfloor =k\) 。
我们再进行第二次做除法下取整,即求 \(\lfloor\frac{m}{k}\rfloor\)
当 \(k \leq a[i]\) 时:
-
若 \(b < k\) ,余数不足以向前进位,显然有 \(\lfloor\frac{m}{k}\rfloor =a[i]\)。
-
若 \(b \ge k\) ,存在 \(t>0\) ,使得 \(\lfloor\frac{m}{a[i]}\rfloor = k*(a[i]+t)+b-kt\) ,其中 \(b-kt<k\) 。则 \(\lfloor\frac{m}{k}\rfloor =a[i]+t\) 。
当 \(k > a[i]\) 时:
- 有 \(k>a[i]>b\),余数不足以进位,显然 \(\lfloor\frac{m}{a[i]}\rfloor =k\) 。
在第二次做除法下取整后,我们用以上方法表达的余数必定 \(<a[i]\) 且 \(<\lfloor\frac{m}{a[i]}\rfloor\) 。最终得到的整除结果在 \(k\) 和 \((a[i]+t)\) 中两者中循环( \(t\) 可能为 \(0\) )。
由此我们发现得到的严格最大结果可能是第一次整除,或第二次整除。
问题转化为区间覆盖问题。我们需要的最大覆盖次数为 \(2\) ,而如果一个格子与一段连通块(或只有自身)一起被覆盖,覆盖次数显然不会超过 \(2\) ,而一个格子若同时被两个连通块覆盖而本身不需要更多次的覆盖,则可以忽略此格子分别选择其他两个连通块,操作次数均为 \(2\) 次,由此我们可以证明任何格子不覆盖超过 \(2\) 次即可获得最优解。
一个格子可能必须被覆盖 \(2\) 次或 \(1\) ,或可以被覆盖 \(2\) 次 或 \(1\) 次,或任意次数均可。贪心显然无法兼顾如此多约束,但一个格子选取次数定后,后一个格子可以选择跟随选取,或少选以及多选,如果少选无需付出次数,多选则额外付出超过的次数,于是用动态规划解决这个问题。
令 \(f[i][j]\) 表示第 \(i\) 位覆盖 \(j\) 次的最小代价。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100001];
int f[100001][3];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
ll m, ans = 0;
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 0; i <= 2; ++i) for (int j = 0; j <= n; ++j) f[j][i] = 0x3f3f3f3f;
f[0][0] = 0;
for (int i = 1; i <= n; ++i) {
if (m / a[i] > a[i]) f[i][1] = min(f[i - 1][1], min(f[i - 1][2], f[i - 1][0] + 1));
else if (m / a[i] == a[i])
f[i][0] = min(min(f[i - 1][0], f[i - 1][1]), f[i - 1][2]), f[i][1] =
min(f[i - 1][1], min(f[i - 1][2], f[i - 1][0] + 1)), f[i][2] = min(
min(f[i - 1][1] + 1, f[i - 1][2]), f[i - 1][0] + 2);
else if (m / (m / a[i]) > a[i]) f[i][2] = min(min(f[i - 1][1] + 1, f[i - 1][2]), f[i - 1][0] + 2);
else
f[i][0] = min(min(f[i - 1][0], f[i - 1][1]), f[i - 1][2]), f[i][2] = min(
min(f[i - 1][1] + 1, f[i - 1][2]), f[i - 1][0] + 2);
ans += max(m / a[i], m / (m / a[i]));
}
cout << ans << ' ' << min(f[n][0], min(f[n][1], f[n][2])) << '\n';
}
return 0;
}

动态规划,线性规划,数论
浙公网安备 33010602011771号