UR #1

Yaosicheng124發表於2024-10-04

A. 縮排最佳化

題目描述

\(N\) 行,每行有 \(A_i\) 個空格。你可以選擇一個預設 TAB 長度 \(x\)。並用一個 TAB 替換 \(x\) 個空格。求最終需要 TAB 和空格數量之和的最小值。

思路

我們先對值的出現次數做一個字首和,然後列舉 \(x\)。並列舉 \(x\) 的倍數再統計答案即可。這樣是一個調和級數的複雜度。

空間複雜度 \(O(N)\),時間複雜度 \(O(N\log N)\)

程式碼

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXV = 1000001;

int n, sum[MAXV];
ll ans = (ll)(1e18), cnt[MAXV];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  for(int i = 1, x; i <= n; ++i) {
    cin >> x;
    sum[x]++;
    cnt[x] += x;
  }
  for(int i = 1; i < MAXV; ++i) {
    sum[i] += sum[i - 1];
    cnt[i] += cnt[i - 1];
  }
  for(int i = 1; i < MAXV; ++i) {
    ll res = 0;
    for(int j = 0; i * j < MAXV; ++j) {
      res += 1ll * j * (sum[min(MAXV - 1, i * (j + 1) - 1)] - (!j ? 0 : sum[i * j - 1])) + (cnt[min(MAXV - 1, i * (j + 1) - 1)] - (!j ? 0 : cnt[i * j - 1])) - 1ll * i * j * (sum[min(MAXV - 1, i * (j + 1) - 1)] - (!j ? 0 : sum[i * j - 1]));
    }
    ans = min(ans, res);
  }
  cout << ans;
  return 0;
}

B. 外星人

題目描述

給定一個數 \(x\),和一個數列 \(A\),你要找到一個排列 \(P\),使得 \(x\bmod A_{P_1}\bmod A_{P_2}\bmod \dots \bmod A_{P_N}\) 最大。並求出有多少個這樣的 \(P\)

思路

顯然當我們模完一個較小的數後,再模較大的數就沒有意義了,所以如果我們想跳過一個數,那麼只需把它丟到更小的數後面。因此先對 \(A\) 從大到小排序。

\(dp_{i,x}\) 表示考慮前 \(i\) 個數,當前數變成了 \(x\) 的方案數。如果我們選擇模,那麼有轉移 \(dp_{i+1,x\bmod A_{i+1}}\leftarrow dp_{i,x}\)。如果不模,那麼 \(dp_{i+1,x}\leftarrow dp_{i,x}\cdot (N-i)\)。最後看最大有方案數的答案即可。

時空複雜度均為 \(O(Nx)\)

程式碼

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1001, MAXV = 5001, MOD = 998244353;

int n, x, a[MAXN], dp[MAXN][MAXV];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> x;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
  }
  sort(a + 1, a + n + 1, greater<int>());
  dp[0][x] = 1;
  for(int i = 0; i < n; ++i) {
    for(int j = 0; j <= x; ++j) {
      dp[i + 1][j] = (dp[i + 1][j] + 1ll * dp[i][j] * (n - i - 1) % MOD) % MOD;
      dp[i + 1][j % a[i + 1]] = (dp[i + 1][j % a[i + 1]] + dp[i][j]) % MOD;
    }
  }
  for(int i = x; i >= 0; --i) {
    if(dp[n][i]) {
      cout << i << "\n" << dp[n][i];
      return 0;
    }
  }
  return 0;
}

相關文章