Codeforces Round #823 (Div. 2) A - D 题解

A - Planets Link

题意:给你N个物品,每个物品类型是a[i],消除任意一个物品的代价为1,消除一个类型的物品代价为C,问消除全部物品的最小代价

数据范围:1\leqslant N, C\leqslant 100, 1\leqslant a_i\leqslant 100

思路:贪心,当某个类型的物品数量大于等于C时,使用C代价消除,否则使用该类型物品数量为代价消除

Code:

void solve() {
    int n, c;
    cin >> n >> c;
    vector<int> a(101);
    for(int i = 0; i < n; i ++ ) {
        int x;
        cin >> x;
        a[x] ++;
    }
    int ans = 0;
    for(int i = 0; i <= 100; i ++ ) {
        if(a[i] > c) {
            ans += c;
        }else {
            ans += a[i];
        }
    }
    cout << ans << endl;
}

B - Meeting on the Line Link

题意:有N个人住在坐标线上,每个人的位置为x_i,每个人有准备时间t_i,现在你需要找出一个点x_0,使得 \left | x_i - x_0 \right | + t_i 的最大值最小

数据范围:1\leqslant N\leqslant 10^5, 0\leqslant x_i, t_i\leqslant 10^8

思路:三分x_0,在x_0处取得函数最小值,向x_0两边走会导致函数值增大,还有二分和贪心的做法

Code:

int x[maxn], t[maxn], n;

double check(double c) {
    double ans = 0;
    for(int i = 0; i < n; i ++ ) {
        ans = max(ans, abs(c - x[i]) + (double)t[i]);
    }
    return ans;
}
 
void solve() {
    cin >> n;
    for(int i = 0; i < n; i ++ ) {
        cin >> x[i];
    }
    for(int i = 0; i < n; i ++ ) {
        cin >> t[i];
    }
    double L = 0, R = 2e8;
    while(abs(R - L) > 1e-6) {
        double mid1 = L + (R - L) / 3;
        double mid2 = R - (R - L) / 3;
        double check1 = check(mid1);
        double check2 = check(mid2);
        if(check1 <= check2) {
            R = mid2;
        }else {
            L = mid1;
        }
    }
    cout << L << endl;
}

 C - Minimum Notation Link

题意:给你一个字符串S,保证'0' \leqslant S_i\leqslant '9',你有一个操作,你可以选择一个下标 i ,删除S_i并在任意一个位置插入min(S_i + 1,'9'),找到可以达到的最小字典序

数据范围:1\leqslant |S|\leqslant 2e5

思路:贪心,我们将字符和下标存为一个pair对,并对字符排序后,我们会发现我们需要保留的就是从第一个元素的下标开始递增的下标上的字符,剩下的加一和9取min,再排序一次直接输出即可

Code:

void solve() {
    vector<pair<char, int>> ve;
    string s;
    cin >> s;
    int n = s.size();
    for(int i = 0; i < n; i ++ ) {
        ve.pb({s[i], i});
    }
    sort(all(ve));
    int now = -1;
    for(int i = 0; i < n; i ++ ) {
        if(ve[i].se > now) {
            now = ve[i].se;
        }else {
            ve[i].fi = (char)min(ve[i].fi + 1, (signed)'9');
        }
    }
    sort(all(ve));
    for(int i = 0; i < n; i ++ ) {
        cout << ve[i].fi;
    }
    cout << endl;
}

D - Prefixes and Suffixes Link

题意:给你两个长度为N的字符串s_1, s_2,你拥有一个操作:

        选择一个整数 k(1\leqslant k\leqslant N),选中s_1中长度为k的前缀,选中s_2中长度为k的后缀,交换

问:能否通过任意次操作(可能为0次)使得 s_1=s_2

数据范围:1\leqslant N\leqslant 1e5

思路:我们手摸这个操作,会发现这个操作实质上就是选择 s_1_i 和 s_2_{(n-i-1)} 两个字符进行交换(0-index):

那么这个操作就绑定了字符 s_1_i 和 s_2_{(n-i-1)},他们只能互相交换,不能和其他对交换,这样的话必须保证相同无序对( s_1_i , s_2_{(n-i-1)} )的数量是偶数;如果是奇数并且  s_1_i 不等于 s_2_{(n-i-1)} ,是无论如何也不可能让s_1, s_2相等的;如果是奇数且有 s_1_i 等于 s_2_{(n-i-1)} ,我们记录一下这样的对的数量,如果大于1也是不行的,如果等于1,我们可以让这一个独立的对放在正中间即可。

Code:

void solve() {
    int n;
    cin >> n;
    string s1, s2;
    cin >> s1 >> s2;
    map<pair<char, char>, int> mp;
    for(int i = 0; i < n; i ++ ) {
        mp[minmax(s1[i], s2[n - i - 1])] += 1;
    }
    int f = 1, t = 0;
    for(auto [x, y] : mp) {
        if(y & 1) {
            t += 1;
            if(x.fi != x.se) {
                f = 0;
                break;
            }
        }
    }
    if(t > 1) f = 0;
    yon(f);
}

 第一次写题解,如有问题请在评论区告知我

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值