1. 程式人生 > 其它 >Codeforces Round #727 (Div. 2) A~D

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

A.Contest Start

  • 題意:有n名選手進行比賽,第i位選手的開始時間位(i - 1) * x,每位選手比賽的持續時間均為t,例如第1位選手開始比賽時間為:0,結束時間為:t, 第2位選手開始時間為x, 結束時間為x + t。每一位選手的不滿意度為該選手到比賽結束時間, 比賽仍未結束(或者比賽剛開始)選手的數量,求所有選手不滿意度之和。
  • 思路:分類討論 + 思維
  • 解析:感覺自己的分類討論寫的有點麻煩(比賽的時候瞎搞),這裡記錄一下看到其他大佬的解法。(首先令cnt = t / x)
    1. 若 cnt >= (n-1)說明當每個人比賽結束時,它身後的所有人都開始比賽(並且仍未結束),此時總的不滿意度為sum(n-1, n-2, n-3 ···, 1),為一個等差數列求和;
    2. 否則,令num = n - cnt, num表示不滿意度為cnt的人數,相當於第一個到第num個人的不滿意度均為cnt,他們的不滿意度總和為num * cnt,而到第num + 1個人時, 它身後已經沒有cnt個人,所以第num + 1 -> 第n個人的不滿意度之和為(cnt-1, cnt-2, ··· 1)的求和, 兩者再進行相加即可。
  • 程式碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int k;
ll n, x, t;
int main()
{
    cin >> k;
    while(k --)
    {
        ll res = 0;
        cin >> n >> x >> t;
        ll cnt = t / x;
        if(cnt >= n - 1)
            res = n * (n-1) / 2;
        else
        {
            ll num = n - cnt;
            res = num * cnt + cnt * (cnt-1) / 2;
        }
        cout << res << endl;
    }
    return 0;
}

B.Love Song

  • 題意:給出一個由a-z組成的字串str, 若有a則a重複一次, 有b則b重複兩次, 有c則重複三次,例如:abbcb,完成變換後:abbbbcccbb,給定一個[l, r]區間, 求該str在該區間根據上訴規則變換後字串str'的長度
  • 思路:字首和
  • 解析:將原區間做一個字首和預處理,記錄完成變換操作後整個字串的長度和,最後通過sum(r) - sum(l-1)即為結果。
  • 程式碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, q;
char str[N];
ll sum[N];
int main()
{
    cin >> n  >> q;
    cin >> str + 1;
    for(int i = 1; i <= n; i++)
        sum[i] += sum[i-1] + (ll)(str[i] - 'a') + (ll)1;
    while(q --)
    {
        int l, r;
        cin >> l >> r;
        cout << sum[r] - sum[l-1] << endl;
    }
    return 0;
}

C.Stable Groups

  • 題意:給出n個學生的成績,若相鄰的兩個學生成績之差不超過x,則該兩個學生可以在一個穩定小組中,並且可以在這n個學生中加入任意成績的k個學生,換言之,也就是將會有n名學生成績已知,可有k名學生成績任意,問這n + k名學生最少能組成幾個穩定小組(k名學生可用可不用,相當於是一個輔助條件,可以幫助組成更少的穩定小組)
  • 思路:貪心 + 思維
  • 解析:首先將n名學生按成績從小到大進行排序。
    1. 只有一名學生時特判一下;
    2. 否則當兩個學生成績差大於x時,按它們之間距離從小到大新增輔助學生(輔助學生就是那k名學生)(貪心思想)
      這裡解釋一下程式碼中的num陣列,實際上是這兩名學生中至少需要插入num名輔助學生的數量才能使得這兩名學生在一個穩定小組,最後是根據num從小到大進行排序的,原理實際是一樣的,那重點是這個num的求法,實際上是ceil(dis/x)-1【此處可以自行找規律】, 但這裡會爆double,所以向上取整利用一個巧妙的規律:ceil(dis/x) = (dis + x - 1) / x即可,最後再根據一些條件消耗輔助學生減少穩定小組的數量即可。
  • 程式碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
ll num[N] ,a[N];
ll n, k, x;
int cnt = 0;
int main()
{
    cin >> n >> k >> x;
    for(int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + 1 + n);
    if(n == 1) cout << 1 << endl;
    else
    {
        for(int i = 2; i <= n; i++)
        {
            ll dis = a[i] - a[i-1];
            if(dis > x)
                num[++cnt] = (dis + x - 1) / x - 1;
        }
        sort(num + 1, num + cnt + 1);
        int tcnt = cnt;
        for(int i = 1; i <= tcnt && k >= num[i]; i++)
        {
            k -= num[i];
            cnt --;
        }
        cout << cnt + 1<< endl;
    }
    return 0;
}

D.PriceFixed

  • 題意:需要購買n種商品,每種商品所需購買的數量為ai, 當購買商品的總數量達到bi,則第i件商品價格為原來的價格的一半,求購買n件商品的最小花費。
  • 思路:貪心 + 雙指標
  • 題解:根據題意,若想要最小花費購買完n種物品,那必然是希望更多的種類物品(準確來說是更多件物品)在購買時能打折,因為購買的單價都一樣,說明每種物品的價值都一樣,那麼我們可以按照bi將物品種類進行排序,也就是先購買容易打折的物品,我們可以設定一個雙指標進行遍歷,將會出現兩種情況:
    1. 當購買第i種商品可以打折時,直接購買ai件第i種商品即可(此時能打折,不買白不買);
    2. 當購買第i種商品不能打折時,那就從尾指標r往前遍歷,先購買b較大的商品進行湊數,總商品數量湊夠bi後再購買第i種商品,這樣就儘可能的多購買到打折的商品。
  • 程式碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n;
struct P
{
    ll a, b;
}p[N];
bool cmp(P x, P y)
{
    return x.b < y.b;
}
int main()
{
    ll sum = 0, cnt = 0; //總花費、當前已購買商品的數量
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> p[i].a >> p[i].b;
        sum += p[i].a * (ll)2;
    }
    sort(p + 1, p + 1 + n, cmp);
    int l = 1, r = n;
    while(l <= r)
    {
        if(cnt >= p[l].b) //當前商品所需數量達到打折的數量
        {
            cnt += p[l].a;
            sum -= p[l].a; //打折的商品數量
            l ++;
        }
        else
        {
            if(p[r].a + cnt >= p[l].b)
            {
                p[r].a -= p[l].b - cnt;
                cnt = p[l].b;
            }
            else //加上第r種商品仍不滿足第l種商品能打折
            {
                cnt += p[r].a;
                r --;
            }
        }
    }
    cout << sum << endl;
    return 0;
}