Codeforces Round 968 (Div. 2)

题目链接:Codeforces Round 968 (Div. 2) - Codeforces
总结:C题想到了,但是写成shi了,出得有点慢。

A. Turtle and Good String

tag:签到

Solution:直接判断第一个字符是否与最后一个字符相等即可。

void solve(){
    cin >> n;
    string s;
    cin >> s;
    if (s[0] == s[n - 1]){
        cout << "No\n";
    }
    else{
        cout << "YES\n";
    }
}

B. Turtle and Piggy Are Playing a Game 2

tag:博弈论

Solution:显然每次操作要么是删除最小值,要么是删除最大值。排序后输出中间值即可。

void solve(){
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i ++){
        cin >> a[i];
    }
    sort(a.begin(), a.end());
    cout << a[n / 2] << endl;
}

C. Turtle and Good Pairs

tag:思维

Description:给定一个字符串 s s s,对于一对整数 ( i , j ) (i, j) (i,j),当 s i = = s j si == sj si==sj或者存在一个整数 k k k,使得 s k ! = s k + 1 s_k != s_{k + 1} sk!=sk+1,且 s k ! = s i ∣ ∣ s k + 1 ! = s j s_k != s_i || s_{k + 1} != s_j sk!=si∣∣sk+1!=sj ( i , j ) (i, j) (i,j)为一对好的配对。将字符串重排,使好的配对数最大。

Solution:我们令 k = = i k == i k==i,那么只要 s i + 1 ! = s i 且 s i + 1 ! = s j s_{i + 1} != s_{i} 且 s_{i + 1} != s_{j} si+1!=sisi+1!=sj即可,那么显然我们需要尽可能多的相邻两个字符不同的组合即尽可能使相邻两个字符不同。

  • 其实只需要按顺序排列字符即可,多的字符全放在后面。

Competing:没仔细想,认为尽可能使相邻字符不同,因此需要判断出现次数最多的字符。

void solve(){
    cin >> n;
    cin >> s;
    int ma = 0;  // 出现次数最多的字符
    char c;
    map<char, int> mp;
    vector<int> a(26);
    for (int i = 0; i < n; i ++){
        mp[s[i]] ++;
        if (mp[s[i]] > ma){
            ma = mp[s[i]];
            c = s[i];
        }
        a[s[i] - 'a'] ++;
    }
    if (ma < n - ma + 1){
        string ans = "";
        int c = 0;
        while (c < n){
            for (int i = 0; i < 26; i ++){
                if (a[i]){
                    a[i] --;
                    ans += char(i + 'a');
                    c ++;
                }
            }
        }
        cout << ans << endl;
    }
    else{
        string ans = "";
        int cnt = 0;
        a[c - 'a'] = 0;
        bool flag = true;
        while (cnt < n && flag){
            flag = false;
            for (int i = 0; i < 26; i ++){
                if (a[i]){
                    a[i] --;
                    ans += c;
                    ma --;
                    ans += char(i + 'a');
                    cnt ++;
                    flag = true;
                }
            }
        }
        while (ma){
            ans += c;
            ma --;
        }
        cout << ans << endl;
    }
}

D1. Turtle and a MEX Problem (Easy Version)

tag:思维

Description:给定 n n n个序列,以开始有一个非负整数 x x x

  • 每次操作可以任选一个序列,令 x = m e x ( x , a 1 , a 2 , . . . , a n ) x = mex(x, a_1, a_2, ..., a_n) x=mex(x,a1,a2,...,an)。即 f ( x ) f(x) f(x)为初始值为 x x x,操作之后可以得到的最大值。
  • 给定一个 m m m,求 ∑ 0 m f ( m ) \sum_{0}^{m}f(m) 0mf(m)

Solution:对于每个序列,我们最多操作两次,可以得到每个序列的第二个 m e x 2 mex2 mex2。那么当 x x x小于最大的 m e x 2 mex2 mex2时,将其变成 m e x 2 mex2 mex2,否则使用 x x x本身。

void solve(){
    cin >> n >> m;
    vector<pii> a(n);
    int ma = 0;
    for (int i = 0; i < n; i ++){
        int len;
        cin >> len;
        vector<int> t(len + 10);
        for (int j = 0; j < len; j ++){
            int x;
            cin >> x;
            if (x < len + 10)
                t[x] = 1;
        }
        int c = 1;
        for (int j = 0; j <= len + 5 && c <= 2; j ++){
            if (!t[j] && c == 1){
                a[i].fi = j;
                c ++;
            }
            else if (!t[j]){
                c ++;
                a[i].se = j;
                ma = max(ma, j);
                break;
            }
        }
    }
    int ans = 0;
    if (m <= ma){
        ans += (m + 1) * ma;
    }
    else{
        ans += (ma + 1) * ma;
        ans += (ma + 1 + m) * (m - ma) / 2;
    }
    cout << ans << endl;

}

D2. Turtle and a MEX Problem (Hard Version)

tag:思维

Solution:和D1的唯一区别时,在一次操作中每个序列最多使用一次。

  • 对于第 i i i个序列,我们建一条有向边 u i − > v i u_i -> v_i ui>vi。那么一次操作 x x x可以沿着一条出边移动,或者移动到一个任意点 u u u,并断开它的出边。
  • 我们先倒序处理一下,令 b i b_i bi等于 i i i能够到达的最大值,我们先倒序处理一下。
  • 首先一个 x x x的答案至少是 f x f_x fx,所有 x x x的答案至少是 max ⁡ 1 n u i \max_{1}^{n}u_i max1nui;对于所有出度大于 1 1 1 i i i x x x的答案至少是 f i f_i fi
  • 实现步骤:倒序处理 f i f_i fi、记录每个点的出度、记录度大于 1 1 1的最大的 f i f_i fi、记录最大的 u i u_i ui
void solve(){
    cin >> n >> m;
    vector<pii> a(n);
    int ma = 0;
    for (int i = 0; i < n; i ++){
        int len;
        cin >> len;
        ma = max(ma, len);
        vector<int> t(len + 10);
        for (int j = 0; j < len; j ++){
            int x;
            cin >> x;
            if (x < len + 10)
                t[x] = 1;
        }
        int c = 1;
        for (int j = 0; j <= len + 5 && c <= 2; j ++){ // 处理u,v的值
            if (!t[j] && c == 1){
                a[i].fi = j;
                c ++;
            }
            else if (!t[j]){
                c ++;
                a[i].se = j;
                break;
            }
        }
    }
    sort(a.begin(), a.end(), 
    [&](pii a, pii b){
        return a.fi > b.fi;
    });
    int mma = 0;  // 最大的ui
    vector<int> b(ma + 10);
    vector<int> chu(ma + 10);
    for (auto [x, y] : a){  // 倒序处理
        mma = max(mma, x);
        int t = max(y, b[y]);
        b[x] = max(b[x], t);
        chu[x] ++;
    }
     
    int t2 = -1;  // 度大于2的,最大的bi
    for (auto [x, y] : a){
        if (chu[x] >= 2 && b[x] > t2){
            t2 = b[x];
        }
    }
    int ans = 0;
    for (int i = 0; i <= ma + 5 && i <= m; i ++){
        b[i] = max({i, b[i], t2, mma});
        ans += b[i];
    }
    if (m > ma + 5){
        ans += (ma + 6 + m) * (m - ma - 5) / 2;
    }
   
    cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值