Codeforces Round #727 (Div. 2) A~D题题解

比赛链接:Here

1539A. Contest Start

让我们找出哪些参与者会干扰参与者i。这些是数字在 \(i+1\)\(i+min(t/x,n)\)之间的参与者。所以第一个最大值 \((0,n−t/x)\) 参与者将获得 \(t/x\) 不满意,下一个参与者将比上一个参与者少获得 \(1\) 个不满意。所以总的答案是 \(max(0,n−(t/x)⋅t/x+min(n−1,t/x−1)⋅min(n,t/x)/2\)

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int _; for (cin >> _; _--;) {
        ll n, x, t;
        cin >> n >> x >> t;
        ll ans = 0;
        if (n > t / x) {
            ans = (n - t / x) * (t / x);
            t /= x;
            ans += t * (t - 1) / 2;
        } else ans = n * (n - 1) / 2 ;
        cout << ans << "\n";
    }
}

1539B. Love Song

伪装成字符串的前缀和


【AC Code】

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n, q;
    string s;
    cin >> n >> q >> s;
    vector<int>pre(n + 1);
    for (int i = 0; i < n; ++i)
        pre[i + 1] = pre[i] + (int)(s[i] - 'a' + 1);
    while (q--) {
        int l, r;
        cin >> l >> r;
        cout << pre[r] - pre[l - 1] << "\n";
    }
}

1539C. Stable Groups

给定 \(n\) 个数和 \(k,x\) 两个正整数,现有 \(n\) 个分值为 \(a_i\) 的学生,要求排列后相邻两个学生的差的绝对值不大于x,至多能在序列中插入k个任意分值的学生,最少能把原序列加上新的学生后(可不全加或不加)分为几个满足条件的子序列。


一开始觉得可以写反悔贪心(的确也可以),但模拟的过程发现对两个排序以后的相邻数差值再排序的结果即答案。

即按升序补学生

【AC Code】

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    ll n, k, x;
    cin >> n >> k >> x;
    vector<ll>a(n);
    for (ll &x : a)cin >> x;
    sort(a.begin(), a.end());
    vector<ll>b(n - 1);
    for (int i = 0; i < n - 1; ++i)
        b[i] = max(0ll, (a[i + 1] - a[i] - 1) / x);
    sort(b.begin(), b.end());
    ll cnt = n;
    for (int i = 0; i < n - 1; ++i) {
        if (b[i] <= k) {
            k -= b[i];
            cnt--;
        }
    }
    cout << cnt << "\n";
}

1539D. PriceFixed

要买 \(n\) 种商品,每种商品要买 \(a_i\) 个,每种商品在购买过 \(b_i\) 件任意商品后可以打五折,每件商品原价为2,最少需要多少钱。


很明显单纯为了打折而去买多的商品至少需要1+1元,和直接买没区别,那就是直接贪心了。

【AC Code】

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n;
    cin >> n;
    vector<pair<ll, ll>> v(n);
    for (int i = 0; i < n; ++i) {
        cin >> v[i].second >> v[i].first;
    }
    sort(v.begin(), v.end());
    int il = 0;
    int ir = n - 1;
    ll have = 0;
    ll ans = 0;
    while (il <= ir) {
        while (il <= ir && v[il].first <= have) {
            ans += v[il].second;
            have += v[il].second;
            v[il].second = 0;
            ++il;
        }
        while (ir >= il && v[ir].second == 0)
            --ir;
        if (il > ir) break;
        ll cnt = min(v[il].first - have, v[ir].second);
        v[ir].second -= cnt;
        have += cnt;
        ans += cnt * 2;
    }
    cout << ans << '\n';
}
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n; cin >> n;
    vector<ll>a(n), b(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i] >> b[i];
    }
    ll total = accumulate(a.begin(), a.end(), 0ll);
    ll ans = 2 * total;
    vector<ll>order(n);
    iota(order.begin(), order.end(), 0); // 生从 0 到 N 的连续整数,即 0、1、2、3、……、N。
    sort(order.begin(), order.end(), [&] (int i, int j) {
        return b[i] > b[j];
    });
    ll cnt = total;
    for (ll i : order) {
        ll tmp = max(0ll, min(cnt - b[i], a[i]));
        ans -= tmp;
        cnt -= tmp;
    }
    cout << ans << '\n';
}
posted @ 2021-07-07 20:35  RioTian  阅读(76)  评论(0编辑  收藏  举报