Codeforces Round 1027 (Div. 3)

涨分啦涨分啦,继上次atcoder涨分之后,这次的cf也涨分了。看起来持续训练还是有效果的,总算回归了一点原来的状态了。最近小红书的面试,做到算法题感觉明显自信了很多,自信还是能带来一点加成的,最后面试官直接不让我手撕代码了,直接说你肯定会下个环节吧哈哈。

再回来,看看这次这几道题

A. Square Year

思路:判断某个四位数是否为完全平方数,那么直接打表把完全平方数打出来再查表即可。主要是这题理解题意花了一点时间,要不然还能更快

/*
Author Owen_Q
*/
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1e4 + 5;
const int MAXM = 1e3;


int a[MAXN];

int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    for (int i = 0; i < t; i++) {
        cin >> a[i];
    }
    map<int, int> sqrt;
    for (int i = 0; i <= MAXM; i++) {
        int now = i * i;
        if (now > MAXN) {
            break;
        }
        sqrt.insert({i * i, i});
    }
    for (int i = 0; i < t; i++) {
        if (sqrt.contains(a[i])) {
            cout << sqrt[a[i]] << " " << 0 << endl;
        } else {
            cout << -1 << endl;
        }
    }
    return 0;
}

B. Not Quite a Palindromic String

思路:任意移动01串中数字的位置,看能否使得串刚好包含特定个中心对称的位置。这题就是个找规律。找出01串0和1的数量差,再减半即为最少得对称位置数。最多的位置数即为长度减半。此外,因为每次移动串至少影响两个对称位置数,所以该数量的奇偶性一定保持一致,因此判断一下上下界再判断一下奇偶即可

/*
Author Owen_Q
*/
#include <bits/stdc++.h>

using namespace std;

int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        string s;
        cin >> s;
        int n1 = 0;
        for (int i = 0; i < n; i++) {
            if (s[i] == '1') {
                n1++;
            }
        }
        int n0 = n - n1;
        int mmax = max(n1, n0);
        int mmin = min(n1, n0);
        int kmin = (mmax - mmin) / 2;
        int kmax = n / 2;
        if (mmax % 2 != 0) {
            kmax = (n - 2) / 2;
        }
        if (k >= kmin && k <= kmax && kmin % 2 == k % 2) {
            cout << "YES" << '\n';
        } else {
            cout << "NO" << '\n';
        }
    }
    return 0;
}

C. Need More Arrays

思路:对于一个有序数组,去除部分数字,使得非连续子串数量最多。那当然是找出所有连续子串然后间隔删除。这和上次那个删除数串的题目极其类似,但这就是一个水题,感觉比AB两题都简单,直接过

/*
Author Owen_Q
*/
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 2e5 + 5;

int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int a;
        cin >> a;
        int pre = a;
        int re = 0;
        int current = 1;
        for (int i = 1; i < n; i++) {
            cin >> a;
            if (a == pre + 1) {
                current++;
                pre = a;
            } else if (a > pre + 1) {
                re += (current + 1) / 2;
                current = 1;
                pre = a;
            }
        }
        re += (current + 1) / 2;
        cout << re << endl;
    }
    return 0;
}

D. Come a Little Closer

思路:最多移动一个棋子,移完后用一个矩形覆盖所有棋子,求最小矩形面积。

那么找出所有边界上的棋子往里移即可。记录一下边界和第二边界的位置方便计算移动的区域和移动后的边界。最后注意一下移动前第二边界里矩形已满的场景,这种场景需要额外往外扩一个最小变长即可

/*
Author Owen_Q
*/
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 2e5 + 5;
const int MAXA = 1e9 + 5;

int x[MAXN], y[MAXN];

typedef long long ll;


int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        set<int> movemaxx, moveminx, movemaxy, moveminy, moves;
        int maxx1 = 0, maxy1 = 0, maxx2 = 0, maxy2 = 0, minx1 = MAXA, minx2 = MAXA, miny1 = MAXA, miny2 = MAXA;
        for (int i = 0; i < n; i++) {
            cin >> x[i] >> y[i];
            if (x[i] >= maxx1) {
                maxx2 = maxx1;
                maxx1 = x[i];
                if (x[i] > maxx2) {
                    movemaxx.clear();
                }
                movemaxx.insert(i);
            } else if (x[i] > maxx2) {
                maxx2 = x[i];
            }
            if (x[i] <= minx1) {
                minx2 = minx1;
                minx1 = x[i];
                if (x[i] < minx2) {
                    moveminx.clear();
                }
                moveminx.insert(i);
            } else if (x[i] < minx2) {
                minx2 = x[i];
            }
            if (y[i] >= maxy1) {
                maxy2 = maxy1;
                maxy1 = y[i];
                if (y[i] > maxy2) {
                    movemaxy.clear();
                }
                movemaxy.insert(i);
            } else if (y[i] > maxy2) {
                maxy2 = y[i];
            }
            if (y[i] <= miny1) {
                miny2 = miny1;
                miny1 = y[i];
                if (y[i] < miny2) {
                    moveminy.clear();
                }
                moveminy.insert(i);
            } else if (y[i] < miny2) {
                miny2 = y[i];
            }
        }
        for (auto i: movemaxx) {
            moves.insert(i);
        }
        for (auto i: movemaxy) {
            moves.insert(i);
        }
        for (auto i: moveminx) {
            moves.insert(i);
        }
        for (auto i: moveminy) {
            moves.insert(i);
        }
        ll re = (ll) (maxx1 - minx1 + 1) * (ll) (maxy1 - miny1 + 1);
        // cout << maxx1 << " " << maxy1 << " " << minx1 << " " << miny1 << endl;
        // cout << maxx2 << " " << maxy2 << " " << minx2 << " " << miny2 << endl;
        for (auto i: moves) {
            int remaxx = movemaxx.contains(i) ? maxx2 : maxx1;
            int remaxy = movemaxy.contains(i) ? maxy2 : maxy1;
            int reminx = moveminx.contains(i) ? minx2 : minx1;
            int reminy = moveminy.contains(i) ? miny2 : miny1;
            ll now = (ll) (remaxx - reminx + 1) * (ll) (remaxy - reminy + 1);
            if (now == n - 1) {
                now += (ll) min(remaxx - reminx + 1, remaxy - reminy + 1);
            }
            re = min(re, now);
        }
        cout << re << endl;
    }
    return 0;
}

E. Kirei Attacks the Estate

思路:每个节点本身有一个防御值,其通向根节点的路径上每个路径有一个防御值(等于当前节点防御值依次加/减下一个节点的防御值,没经过一个节点变换一次加减符号)。求每个节点的最大防御值,那么其实只要从根节点开始递归维护每个节点的最大和最小防御值即可

/*
Author Owen_Q
*/
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 2e5 + 5;

typedef long long ll;

ll a[MAXN];

vector<vector<int> > uv;
vector<ll> maxa;
vector<ll> mina;

void dfs(int father, int child) {
    mina[child] = a[child] - maxa[father];
    if (mina[father] < 0) {
        maxa[child] = a[child] - mina[father];
    }
    int lenChild = uv[child].size();
    for (int i = 0; i < lenChild; i++) {
        if (uv[child][i] != father) {
            dfs(child, uv[child][i]);
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        uv.clear();
        maxa.clear();
        mina.clear();
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            vector<int> tmp;
            uv.push_back(tmp);
            maxa.push_back(a[i]);
            mina.push_back(a[i]);
        }
        for (int i = 1; i < n; i++) {
            int u, v;
            cin >> u >> v;
            uv[u - 1].push_back(v - 1);
            uv[v - 1].push_back(u - 1);
        }
        int len1 = uv[0].size();
        for (int i = 0; i < len1; i++) {
            dfs(0, uv[0][i]);
        }
        cout << maxa[0];
        for (int i = 1; i < n; i++) {
            cout << " " << maxa[i];
        }
        cout << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值