Practice.

A. Lucky Numbers

题意

此处给出 \(A\) 题和 \(C\) 题的定义:

对于一个数字,将所有位上的数取出,组成一个序列 \(a\)。定义 \(l = a_{\max} - a_{\min}\)

那么, 给定一个区间 \([l ,r]\)\(l\) 的最大值对应的数就是最幸运数,最小值对应的数就是最不幸运数。

给定一个区间 \([l, r]\),输出任意一个最幸运数。

思路

首先,如果考虑幸运数,那么我们不难发现,我们只需关注十位和个位上的数即可,因为在这里就可以搞出最大值。

那么,暴力遍历 \([l, l + 100]\) 即可。

时间复杂度:\(O(100x)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

void init(){}

void solve() {
    int l, r;
    cin >> l >> r;
    pii ans = {0, l};
    for(int i=l;i<=min(l + 100, r);i++){
        int tmp = i, mn = inf, mx = 0;
        while(tmp > 0){
            int cur = tmp % 10;
            mn = min(mn, cur);
            mx = max(mx, cur);
            tmp /= 10;
        }
        if(ans.fs < mx - mn){
            ans = {mx - mn, i};
        }
    }
    cout << ans.sc << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

为什么我会想着去构造((

B. Playing in a Casino

题意

给定 \(n\) 个人的 \(m\) 张手牌对应的数字,构成序列 \(a_{i,x}\)

遍历 \(i \in [2, n], j \in [1, i - 1]\),统计 \(|a_i[0] - a_j[0]| + |a_i[1] - a_j[1]| + \ldots + |a_i[m] - a_j[m]|\) 的总和。

输出总和。

思路

显然,我们可以直接竖着看,看一下去掉绝对值的情况。

不难发现,我们固定第二维 \(x\),那么对于竖向构造得到的每一个序列,我们进行排序,可以得到形如下面的序列:

\(a, b, c, d, e\)

最后,这个序列的值为 \(-4a-2b+2d+4e\)

或者说,我们只需排序后遍历,乘上权重加起来即可。权重首项为 \(n - 1\),依次递减 \(2\)

时间复杂度:\(O(mn)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

void init(){}

void solve() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> a(m, vector<int>(n));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin >> a[j][i];
    int ans = 0;
    for(int i=0;i<m;i++){
        sort(a[i].begin(), a[i].end());
        for(int j=0;j<n/2;j++) ans += (a[i][n - j - 1] - a[i][j]) * (n - 1 - 2 * j);
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

简简单单(x

C. Unlucky Numbers

题意

给定一个区间 \([l, r]\),输出任意一个最不幸运数。

思路

我们可以考虑用 \(DFS\) 来实现,用拼接的方式得到答案。

考虑下面的两个剪枝:

  1. 当前拼接得到的数可以预测是否一定超出边界,如对于 \(12\),范围为 \([135, 189]\),那么由 \(12 \times 10 + 10 = 130 < 135\) 可知一定不在边界内。另一个边界直接判大小即可。

  2. 因为深搜,所以能提前得到一些答案,那么如果当前 \(\max - \min\) 已经大于之前求得的答案了,就不用继续了。

时间复杂度:不会分析

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

string l, r, ans;
int val = inf, vl, vr;

void init(){}

void dfs(int x, int mn, int mx, const string& now){
    int vn = stoll(now);
    if(x == l.size()){
        if(vn >= vl && vn <= vr && mx - mn < val){
            val = mx - mn;
            ans = now;
        }
        return;
    }
    int exp = vn * pow(10, l.size() - x); //优化一下查找
    if(exp + pow(10, l.size() - x) < vl || exp > vr || mx - mn >= val) return;
    for(int i=0;i<=9;i++) dfs(x + 1, min(mn, i), max(mx, i), now + (char) (i + '0'));
}

void solve() {
    cin >> l >> r;
    vl = stoll(l), vr = stoll(r);
    if(l.size() < r.size()){
        for(int i=0;i<l.size();i++) cout << 9;
        cout << '\n';
    }else{
        ans = "";
        val = inf;
        for(int i=l[0]-'0';i<=r[0]-'0';i++){
            dfs(1, i, i, to_string(i));
        }
        cout << ans << '\n';
    }
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

就很无脑,不知道dp咋做(