T1:分段求平均数

本题难度中等,划分型DP问题。用 dp[i] 表示前 i 个数最少划分成几段,对 j=1,2,,i1 判断从 ajai 划分成一段时,平均数是否为整数,如果是整数,就更新 dp[i]=max(dp[i],dp[j1]+1)

初始值: dp[i]=i

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
vector<int> s(n+1);
rep(i, n) s[i+1] = s[i]+a[i];
vector<int> dp(n+1);
rep(i, n+1) dp[i] = i;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= i; ++j) {
if ((s[i]-s[j-1])%(i-j+1) == 0) {
dp[i] = min(dp[i], dp[j-1]+1);
}
}
}
cout << dp[n] << '\n';
return 0;
}

T2:余数的余数

本题难度较大,n10 直接枚举 a 的所有全排列即可。

k<a 时,kmoda=k 。利用这一性质,计算余数时,如果模了一个较小数 amin,那么如果后面的 aamin 大,这个 a 对最终的余数就没有影响了,所以当确定了 a 数组的顺序后,对最终余数有影响的,只有每次新出现的更小 a

例如 a={7,9,8,6,3,5},第 1mod 7 之后,接下来的 98 对余数都没有影响;接下来的模数是 6,比 7 小,所以会对余数有影响;接下来 mod 336 小,所以会对余数有影响;最后的 53 大,所以对余数都没有影响。最终这个 a 序列中,对余数有影响的只有 {7,6,3} 这个递减序列。

于是我们可以用子集枚举,先枚举出递减序列中的 a,然后按照递减顺序依次计算余数,就可以得到所有可能的余数 x 的值。

代码实现时,先把 a 排序成递减顺序再枚举子集比较好写。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<int> a(n);
rep(i, n) cin >> a[i];
sort(a.rbegin(), a.rend());
int ans = 0;
auto dfs = [&](auto f, int i, int r) -> void {
if (r <= ans) return;
if (i == n-1) {
ans = max(ans, r%a[n-1]);
return;
}
f(f, i+1, r);
f(f, i+1, r%a[i]);
};
dfs(dfs, 0, k);
cout << ans << '\n';
return 0;
}