Divide by Zero 2021 and Codeforces Round #714 (Div. 2) 我的補題記錄

補題連接:Hereios

A. Array and Peaks

題意:給定 數組大小 \(n\) 和 峯值點 \(k\) 請問是否存在這樣的排序,不存在則輸出-1數組

先序從 i = 2 開始填,依次 i += 2 ,若是這樣還有不夠即 \(k \ne 0\) 則確定不存在這種排序。spa

接下來就是填空位了code

AC 代碼:排序

void solve() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n + 1);
    int nn = n;
    for (int i = 2; i <= n; i += 2) {
        if (k == 0) break;
        a[i] = nn--, k--;
    }
    if (k) {
        cout << -1 << "\n";
        return;
    }
    int cur = 1;
    for (int i = 1; i <= n; ++i)
        if (!a[i]) a[i] = cur++;
    for (int i = 1; i <= n; ++i) cout << a[i] << " ";
    cout << "\n";
}

B. AND Sequences

這道題,還是看了題解都沒怎麼理解是這樣子作的ci

using ll     = long long;
const ll mod = 1e9 + 7;
void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int &x : a) cin >> x;
    int h = 0;
    for (int i = 0; i < 30; ++i) {
        h |= 1 << i;
        for (int x : a)
            if (not((x >> i) & 1)) h &= ~(1 << i);
    }
    int c  = count(a.begin(), a.end(), h);
    ll ans = (ll)c * (c - 1) % mod;
    for (int i = 1; i <= n - 2; ++i) ans = ans * i % mod;
    cout << ans << '\n';
}

C. Add One

題意很容易懂:現給一個大數 \(n\)\(m\) 次操做機會,每次操做都要使 \(n\) 的每一個位數 + 1,滿十進一。如:\(1912 \to21023\)字符串

思路:get

因爲 \(m\) 的範圍在 \([1,2e5]\) 就別想着暴力了,嘗試 DP + 預處理string

預處理部分: $DP_{(i,j)}\ $ 表明第 i 次操做時位數值時 j 的變化值it

\[init:dp[0][i] = 1\\ dp(i,j) = j < 9\ ?\ dp(i - 1,j + 1) : (dp(i-1,0) + dp(i - 1,1)\ \%\ mod) \]

int M = 2e5 + 10;
vector<vector<int>> dp(M + 1, vector<int>(10));
void init() {
    for (int i = 0; i < 10; ++i) dp[0][i] = 1;
    for (int i = 1; i <= M; ++i)
        for (int j = 0; j < 10; ++j) {
            if (j < 9) dp[i][j] = dp[i - 1][j + 1];
            else
                dp[i][j] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
        }
}

因此根據 DP 數組,能夠快速獲得輸入值 n,m的狀況下最後的位數

void solve() {
    string s;
    int m;
    cin >> s >> m;
    ll ans = 0;
    for (char c : s) ans = (ans + dp[m][c - '0']) % mod;
    cout << ans << "\n";
}

賽後看了下官方題解,發現能夠把二維DP壓縮爲一位DP

\(dp_i\) 定義爲對數字 \(10\) 進行 \(i\) 次運算之後的字符串長度

  • \(dp_i = 2,∀\ i\) in \([0,8]\)

  • \(dp_i = 3,\) if \(i = 9\)

    即對數字 \(10\) 進行 \(9\) 次運算後最終數字爲 \(109\)

  • 對於其餘狀況:\(dp_i = dp_{i-9} + dp_{i - 10}\)

    長度是 \(i - 9\) 次運算和 \(i - 10\) 次運算的和

這裏一樣先預處理

最後的答案爲 \(ans = \sum_{i = 1}^{|s|}((m + (int)(s[i] - '0') < 10)?1:dp_{m-10+(int)(s[i] - '0')})\)

  • 時間複雜度爲:\(\mathcal{O}(m+t·|s|)\)
#define int long long
const int max_n = 200005, mod = 1000000007;
int dp[max_n];
signed main() {
    for (int i = 0; i < 9; i++) dp[i] = 2;
    dp[9] = 3;
    for (int i = 10; i < max_n; i++) {
        dp[i] = (dp[i - 9] + dp[i - 10]) % mod;
    }
    ios_base::sync_with_stdio(false), cin.tie(NULL);
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        int ans = 0;
        while (n > 0) {
            int x = n % 10;
            ans += ((m + x < 10) ? 1 : dp[m + x — 10]);
            ans %= mod;
            n /= 10;
        }
        cout << ans << "\n";
    }
    return 0;
}
相關文章
相關標籤/搜索