Codeforces1003(Div4 A-F)

目录

A. Skibidus and Amog'u

B. Skibidus and Ohio

C. Skibidus and Fanum Tax (C1,C2)

D. Skibidus and Sigma

E. Skibidus and Rizz

F. Skibidus and Slay


A. Skibidus and Amog'u

题目链接:https://codeforces.com/contest/2065/problem/A

没有什么特别的,根据题目直接模拟即可

void solve() {
    string s;
    cin >> s;

    int len = s.length();
    for (int i = 0;i < len - 2;i++) cout << s[i];
    cout << "i" << '\n';
}

B. Skibidus and Ohio

题目链接:https://codeforces.com/contest/2065/problem/B

我们发现如果至少存在一组使得 s[i] == s[i + 1] 那么我们就可以一直操作直到剩最后一个字母

void solve() {
    string s;
    cin >> s;

    int len = s.length();
    for (int i = 0;i < len - 1;i++) {
        if (s[i] == s[i + 1]) {
            cout << 1 << '\n';
            return;
        }
    }

    cout << len << '\n';
}

C. Skibidus and Fanum Tax (C1,C2)

题目链接:https://codeforces.com/contest/2065/problem/C2

由于对每个a[i]都可以独立地使用任意一个 b[j] (且可以重复使用),因此对于每个 i,如果我们选择作,

实际上可以得到任意形如 b − a[i] 的数,其中 b 来自数组 b;

而我们的目标是 "给后面的数留出空间";因此在满足"至少不比前一个数小"的前提下,越小越好.

一种自然的思路是动态规划:

- 1.不操作: 若 a[i] >= dp[i - 1], 则可以令 dp[i] = a[i].

- 2.操作: 如果存在某个b使得操作后的值满足b >= dp[i - 1] + a[i]那么我们可以从数组 b 中选择满足条件的最小值b(我们记为b*), 这样得到的操作结果是 dp[i] = b*-a[i].

最终, 若对某个位置 i 上, 两种选择都不满足条件 (即都无法使 v[i] >= dp[i - 1]),

则说明无法构造出一个非递减序列;

否则, 最后存在一种方案使得整个序列非递减.

对于操作选项, 我们需要找到满足 b >= dp[i - 1] + a[i] 的最小的 b ,

因此我们可以先对数组 b 排序, 再用二分查找来寻找下界.

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> a(n + 1), b(m + 1);
    for (int i = 1;i <= n;i++) cin >> a[i];
    for (int i = 1;i <= m;i++) cin >> b[i];
    sort(b.begin(), b.end());

    int dp = -INF;
    for (int i = 1;i <= n;i++) {
        int sen = INF;
        
        if (a[i] >= dp) sen = a[i];

        int mid = dp + a[i];
        auto pos = lower_bound(b.begin() + 1, b.end(), mid);
        if (pos != b.end()) sen = min(sen, *pos - a[i]);

        if (sen == INF) {
            cout << "NO\n";
            return;
        }

        dp = sen;
    }

    cout << "YES\n";
}

D. Skibidus and Sigma

题目链接:https://codeforces.com/contest/2065/problem/D

由题目所得, 分数的构成是由前缀和来决定, 所以贪心的想法就是把前缀和大的数组放在前面,这样我们就能最大化分数.

void solve() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> v(n + 1, vector<int> (m + 1));

    vector<PII> sen;
    for (int i = 1;i <= n;i++) {
        ll sum = 0;
        for (int j = 1;j <= m;j++) {
            cin >> v[i][j];
            sum += v[i][j];
        }

        sen.push_back({sum, i});
    }

    sort(sen.begin(), sen.end(), greater<PII> ());

    ll ans = 0;
    ll cnt = 0;
    for (auto [sum, pos] : sen) {
        for(int j = 1;j <= m;j++) {
            cnt += v[pos][j];
            ans += cnt;
        }
    }

    cout << ans << '\n';    
}

E. Skibidus and Rizz

题目链接:https://codeforces.com/contest/2065/problem/E

根据题目, 我们需要关注几个点:

- 首先如果 abs(n - m) > k 则无解

- 其次我们判断 n 和 m 的大小分开处理

- 然后我们在判断个数更大的数与k的关系 如果小于 k 则无解

现在我们假设 n > m:

我们可以先输出 k 个0, 再输出 k - (n - m) 个 1 这样操作后 0 和 1 的剩余个数就会一样;

从前面我们知道 abs(n - m) <= k 那么如果 n - m < k 我们就可以直接 101010 这样交替构造;

如果 n - m == k 则 此时只能 010101 这样构造

反之如果 n < m 同理

void solve() {
    int n, m, k;
    cin >> n >> m >> k;

    if (abs(n - m) > k) {
        cout << -1 << '\n';
        return;
    }

    auto f = [&] (char tar, int num1, int num2) -> string {
        string s = "";
        for (int i = 0;i < k;i++) s.push_back(tar);

        char sen = (tar == '1' ? '0' : '1');

        for (int i = 0;i < k - (num1 - num2);i++) s.push_back(sen);

        int len = num1 - k;
        if (num1 - num2 < k) {
            for (int i = 0;i < len;i++) {
                s.push_back(tar);
                s.push_back(sen);
            }
        } else {
            for (int i = 0;i < len;i++) {
                s.push_back(sen);
                s.push_back(tar);
            }
        }

        return s;
    };

    if (n >= m) {
        if (n < k) {
            cout << -1 << '\n';
            return;
        }

        string ans = f('0', n, m);
        cout << ans << '\n';
    } else {
        if (m < k) {
            cout << -1 << '\n';
            return;
        }

        string ans = f('1', m, n);
        cout << ans << '\n';
    }
}

F. Skibidus and Slay

题目链接:https://codeforces.com/contest/2065/problem/F

首先以一个点为中心向四周扩散这种也符合题目要求的简单路径;

假设某条边所连两个点对应值相等,此时为满足条件的最短的路径;

如果并不相等那么我们可以依次判断每个点的所有连边, 例如此时顶点为3(值与后边不同)和他所连的两个点为1, 2值均为5

此时 1 <- 3 -> 2 是满足条件的 我们可以记录对应值出现的个数, 如果个数大于1则满足条件

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1;i <= n;i++) cin >> a[i];

    vector<vector<int>> edge(n + 1, vector<int> ());
    vector<int> ans(n + 1);
    for (int i = 0;i < n - 1;i++) {
        int u, v;
        cin >> u >> v;
        edge[u].push_back(v);
        edge[v].push_back(u);

        if (a[u] == a[v]) ans[a[u]] = 1;
    } 

    for (int i = 1;i <= n;i++) {
        map<int, int> mp;
        for (auto c : edge[i]) mp[a[c]]++;

        for (auto [c, v] : mp) {
            if (v > 1) ans[c] = 1;
        }
    }
    
    for (int i = 1;i <= n;i++) cout << ans[i];
    cout << '\n';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值