Codeforces Round 954 (Div. 3)部分题解A~D+F

A. X Axis

题目大意

给x轴上三点,要求找出一点到三点的距离和最小。

思路

三点中间点即是满足条件最优点。

代码实现
void solve(){
    vector<ll>o(3);
    for (int i = 0; i < 3; i++)cin >> o[i];
    sort(o.begin(), o.end());
    cout << abs(o[1] - o[0]) + abs(o[1] - o[2]) << "\n";
}

B. Matrix Stabilization

题目大意

给定一矩阵,要求让矩阵上每个点都不满足严格大于周围的点,每次只能让一个值减一,求最终矩阵什么样要求最少操作。

思路

判即可。

让不满足的变成周围四个点中最大得的即可。

代码实现
ll dt[210][210];
void solve(){
    ll n, m; cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> dt[i][j];
        }
    }
    ll fx[4][2] = { {0,1},{1,0},{-1,0},{0,-1} };
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            ll sum = 0;
            ll be = 4;
            for (int ii = 0; ii < 4; ii++) {
                ll xx = fx[ii][0] + i;
                ll yy = fx[ii][1] + j;
                if (xx<1 || xx>n || yy<1 || yy> m) {
                    be--;
                    continue;
                }
                if (dt[xx][yy] < dt[i][j])sum++;
            }
            if (be == sum) {
                ll mx = -1e12;
                for (int ii = 0; ii < 4; ii++) {
                    ll xx = fx[ii][0] + i;
                    ll yy = fx[ii][1] + j;
                    if (xx<1 || xx>n || yy<1 || yy> m) {
                        continue;
                    }
                    mx = max(dt[xx][yy], mx);
                }
                dt[i][j] = mx;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cout << dt[i][j] << " \n"[j == m];
        }
    }
}

C. Update Queries

题目大意

给定一个长度为n的字符串,然后给你一个可以任意排序的操作序列,再给一组可以任意排序的字符序列,要求进行完操作的字符串字典序最小。

思路

我们对操作和字符序列进行从小到大排序,对于同一位置的操作,我们可以让他一开始对应较大字典序的字符,然后最后一次用字典序最小的字符。

代码实现
void solve() {
    ll n, m; cin >> n >> m;
    string s; cin >> s;
    vector<ll>o(m);
    for (int i = 0; i < m; i++) {
        cin >> o[i];
    }
    sort(o.begin(), o.end());
    string b; cin >> b;
    sort(b.begin(), b.end());
    deque<char>p;
    for (auto c : b)p.push_back(c);
    queue<char>todo;
    for (int i = 0; i < m - 1; i++) {
        if (o[i + 1] == o[i]) {
            todo.push(p.back());
            p.pop_back();
        }
        else {
            todo.push(p.front());
            p.pop_front();
        }
    }
    todo.push(p.front()); p.pop_front();
    for (int i = 0; i < m; i++) {
        char c = todo.front(); todo.pop();
        s[o[i] - 1] = c;
    }
    cout << s << "\n";
}

D. Mathematical Problem

题目大意

给定一个数字字串,要求加入n-2个加或乘在序列里面,求最小值。

思路

对应n=2的字串,直接输出即可。

对于字符串中存在0的,我们只需要判断0两侧可以都可以加乘号,即可直接输出最小值。

1两边如果可以加的话,让他加乘号最优,初次之外都加加号最优。

对于其他情况,我们让每两个成一组,硬判即可。

代码实现
ll o[210000];
ll num(ll l, ll r) {
    ll sum = 0;
    for (int i = l; i <= r; i++) {
        sum += o[i];
        if (i != r)sum *= 10;
    }
    return sum;
}
void solve() {
    ll n; cin >> n;
    bool flag = false;
    for (int i = 1; i <= n; i++) {
        char c; cin >> c;
        o[i] = c - '0';
        if (o[i] == 0 && ((n == 2 || (n == 3 && i == 2))==false))flag = true;
    }
    if (flag) {
        cout << "0\n"; return;
    }
    if (n == 2) {
        cout << num(1, 2) << "\n"; return;
    }
    ll ans = 1e18;
    for (int i = 1; i < n; i++) {
        ll sum = 0;
        bool flag = 0;
        for (int j = 1; j <= n; j++) {
            ll now = o[j];
            if (j == i) {
                j++; now *= 10; now += o[j];
            }
            if (now == 1) {
                flag = true;
            }
            else {
                sum += now;
            }
        }
        if (sum == 0 && flag) {
            sum = 1;
        }
        ans = min(ans, sum);
    }
    cout << ans << "\n";
}

F. Non-academic Problem

题目大意

给定一个无向图,要求减去图中一个边,使可以互相到达的顶点数量最小。

思路

tarjan求割边板子题。

无向图中,减去一个桥,才可以让答案变化。

我们只需要在判断减下每个桥之后答案的最小值即可。

代码实现
ll n, m;
ll low[MAXN], dfn[MAXN], dfs_clock;
bool isbridge[MAXN];
vector<ll> G[MAXN];
ll cnt_bridge;
ll father[MAXN], siz[MAXN];
ll ans = LLONG_MAX;
void tarjan(int u, int fa) {
    father[u] = fa;
    low[u] = dfn[u] = ++dfs_clock;
    siz[u] = 1;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            siz[u] += siz[v];
            if (low[v] > dfn[u]) {
                isbridge[v] = true;
                ans = min(ans, siz[v] * (siz[v] - 1) / 2 + (n - siz[v]) * (n - siz[v] - 1) / 2);
                ++cnt_bridge;
            }
        }
        else if (dfn[v] < dfn[u] && v != fa) {
            low[u] = min(low[u], dfn[v]);
        }
    }
}
void solve() {
    cin >> n >> m;
    dfs_clock = 0; cnt_bridge = 0;
    ans = LLONG_MAX;
    for (int i = 1; i <= n; i++) {
        father[i] = 0; low[i] = 0; dfn[i] = 0;
        G[i].clear(); isbridge[i] = false;
        siz[i] = 0;
    }
    for (int i = 1; i <= m; i++) {
        ll x, y; cin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    tarjan(1, 0);
    if (ans == LLONG_MAX) {
        cout << n * (n - 1) / 2 << "\n";
        return;
    }
    cout << ans << "\n";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值