T1:奇怪的银行

可以直接把 \(1, 6^p, 9^p\) 当做物品大小,跑一遍完全背包。时间复杂度为 \(\mathcal{O}(n\log n)\)

dp[i][j] 表示前 \(i\) 种面值恰好凑出 \(j\) 元的最少张数

转移:

\[dp[i][j] = \min(dp[i-1][j], dp[i][j-w_i]+1) \]

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

inline void chmin(int& x, int y) { if (x > y) x = y; }

int main() {
    int m;
    cin >> m;
    
    vector<int> w(1, 1);
    for (int i = 6; i <= m; i *= 6) w.push_back(i);
    for (int i = 9; i <= m; i *= 9) w.push_back(i);
    int n = w.size();
    
    const int INF = 1001001001;
    vector<int> dp(m+1, INF);
    dp[0] = 0;
    rep(i, n) {
        for (int j = w[i]; j <= m; ++j) {
            chmin(dp[j], dp[j-w[i]]+1);
        }
    }
    
    cout << dp[m] << '\n';
    
    return 0;
}

T2:用户名已被使用

本题难度较大,首先枚举 \(n\) 个字符串的全排列,然后枚举这些字符串之间下划线的个数。

假设 \(s_i\)\(s_{i+1}\) 之间有 \(x_i\) 个下划线,那么 $$x_1 + x_2 + \cdots + \cdots + x_{n-1} \leqslant 15 - \sum |s| \leqslant 15-n$$

枚举出全排列之后,写一个 \(\operatorname{dfs}\) 枚举每个 \(x_i\) 的值,拼出用户名,然后判断是否已被占用,并将没被占用的用户名存入答案数组。最后将答案数组排序后输出。所有可能的用户名最多可能有 \(n! \cdot C_{15-n}^{n-1}\),当 \(n = 7\) 时,这个值取到最大值 \(141120\)。答案数组的大小要比这个数大。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<string> S(n);
    int len = 0;
    rep(i, n) {
        cin >> S[i];
        len += S[i].size();
    }
    
    sort(S.begin(), S.end());
    
    set<string> ts;
    rep(i, m) {
        string t;
        cin >> t;
        ts.insert(t);
    }
    
    vector<string> ans;
    // cnt 表示已经用了多少个_
    auto dfs = [&](auto f, int step, int cnt, string name) -> void {
        if (step == n-1) {
            name += S.back();
            if (name.size() >= 3 and name.size() <= 15 and !ts.count(name)) {
                ts.insert(name);
                ans.push_back(name);
            }
            return;
        }
        for (int i = 15-len-cnt; i >= 1; --i) {
            string ul(i, '_');
            f(f, step+1, cnt+i, name+S[step]+ul);
        }
    };
    do {
        dfs(dfs, 0, 0, "");
    } while (next_permutation(S.begin(), S.end()));
    
    sort(ans.begin(), ans.end());
    
    if (!ans.size()) {
        puts("-1");
        return 0;
    }
    for (string s : ans) cout << s << '\n';
    
    return 0;
}