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 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> 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

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

Codeforces Round #823 (Div. 2) A - D 题解_第1张图片

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

Code:

void solve() {
    int n;
    cin >> n;
    string s1, s2;
    cin >> s1 >> s2;
    map, 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);
}

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

 

你可能感兴趣的:(Codeforces,算法,c++)