縮排最佳化
我們可以列舉 \(i\) 的所有倍數,我們讓每一塊中的數除以 \(i\) 相等,顯然這是調和集數
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e7 + 5, INF = 1e18;
int n, a[N], sum[N], ans = INF, cnt[N];
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[a[i]] += a[i];
cnt[a[i]]++;
}
for (int i = 1; i <= 2000000; i++) {
sum[i] += sum[i - 1];
cnt[i] += cnt[i - 1];
}
for (int i = 1; i <= 1000000; i++) {
int tmp = 0;
for (int j = 0; j <= 1000000; j += i) {
tmp += (sum[j + i - 1] - sum[max(0ll, j - 1)]) - (j * (cnt[j + i - 1] - cnt[max(0ll, j - 1)]));
tmp += (j / i) * (cnt[j + i - 1] - cnt[max(0ll, j - 1)]);
}
ans = min(ans, tmp);
}
cout << ans;
return 0;
}
外星人
首先如果 \(x \mod a = res\) 那麼 \(res \mod b (b >= a) = res\),所以我們可以直接將 \(a_i\) 送大到小排序,我們設 \(dp_{i, j}\) 表示當前選到了第 \(i\) 個數,當前的數字為 \(j\) ,那麼如果考慮當前這個數不選就是 \(dp_{i, j} += dp_{i - 1, j} \times (n - i)\) 因為當前這個數可以放到後面的 \(n - i\) 個位置 ,如果考慮當前這個數選,那麼就是 \(dp_{i, {j \mod a_i}} += dp_{i - 1, j}\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e3 + 5, mod = 998244353;
int n, x, a[N], dp[N][N];
bool cmp(int _x, int _y) {
return _x > _y;
}
signed main() {
cin >> n >> x;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + n + 1, cmp);
dp[0][x] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= x; j++) {
dp[i][j % a[i]] += dp[i - 1][j];
dp[i][j % a[i]] %= mod;
dp[i][j] += (dp[i - 1][j] * (n - i) % mod);
dp[i][j] %= mod;
}
}
int ans = x;
while (!dp[n][ans]) {
ans--;
}
cout << ans << "\n" << dp[n][ans];
return 0;
}