【无标题】Codeforces Round #782 (Div. 2) A-C

A

链接

题意

给了你n,r,b,r+b=n,r>b,n表示字符串长度,r表示’R’的个数,b表示’B’的个数,现在让你求一个字符串,其中连续的R最小。

思路

首先b个B最多可以将r个R分成b+1段,那么每一段中,包含的R的数量为:r/(b+1),那么现在均分完后,剩余r的数量为:r-(b+1) * b,剩余的r依次假如每一段中,这个时候得到的就是连续的R的数量最小:

#include <bits/stdc++.h>

#define int long long

using namespace std;

void solve()
{
    int n, r, b; cin >> n >> r >> b;

    int num = r / (b + 1);
    int rest = r - num * (b + 1);

    for (int i = 1; i <= b + 1; i ++)
    {
        if (rest) { cout << 'R'; rest --; }
        for (int j = 1; j <= num; j ++) cout << 'R';
        if (i != b + 1) cout << 'B';
    }

    cout << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);

    int t; cin >> t;
    while (t --) solve();

    return 0;
}

B

链接

题意

给了你一个长度为n的01字符串,你最多可以做n次操作,每次选择一个位置,这个位置不变,其他位置0->1,1->0,问你怎样变化能使这个字符串的字典序最大,输出变化之后的字符串,在输出每个位置变化的次数。

思路

首先,如果一个位置变化的次数是奇数次,那么这个位置的值会变化,如果这个位置变化的次数是偶数次,那么这个位置的值不会变化,所我们需要根据最大操作次数的奇偶来分别判断:
1、当k是奇数的时候,对于以为位置,如果该位置是1,那么我们不对它进行操作,因为总共会执行k次,而k是奇数,那么这个位置相当于执行了奇数次,最终会变成0,如果这个位置是偶数,那么我们对它执行一次,相当于最终进行了k-1次,那么执行了偶数次,最终会变成1。当我们从开头到结尾遍历了一遍这个字符串后,如果可执行的操作次数还有剩余,我们直接将它加到最后一个字符,如果剩余的次数是偶数,那么加在最后一个位置,对结果的影响是最小的,如果是奇数次,对结果不会有影响。
2、当k是偶数的时候同理。

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int N = 2e5 + 10;

int a[N];

void solve()
{
    int n, k; cin >> n >> k;
    string s; cin >> s;
    int tmp = k;

    for (int i = 0; i < n; i ++) a[i] = 0;

    if (k % 2 == 1)
    {
        for (int i = 0; i < n; i ++)
        {
            if (s[i] == '1' && k != 0) { a[i] = 1; k --; }
            if (!k) break;
        }

        if (k) a[n - 1] += k;
    }
    else
    {
        for (int i = 0; i < n; i ++)
        {
            if (s[i] == '0' && k != 0) { a[i] = 1; k --; }
            if (!k) break;
        }
        if (k) a[n - 1] += k;
    }

    for (int i = 0; i < n; i ++)
    {
        if ((tmp - a[i]) % 2 == 0) cout << s[i];
        else cout << ((s[i] - '0') ^ 1);
    }
    cout << endl;
    for (int i = 0; i < n; i ++) cout << a[i] << ' ';
    cout << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);

    int t; cin >> t;
    while (t --) solve();

    return 0;
}

C

链接

题意

你是一个国王,你的首都在0位置,现在告诉你还有n个位置没有被占领,你现在要将它们都占领了,你现在可以执行两种操作,第一种,直接占领,所需要的花费是a*(c[2] - c[1]),(1表示当前位置,2表示占领的位置),第二种,移动首都,所需要的花费是b*(c[2] - c[1]),占领地区,首都和占领的地区之间不能有未被占领的地区。让你求最小的花费。不用管首都最终的位。

思路

首先给你的为占领的地区是按照递增的顺序的,那么就可以想到二分,二分的内容是,首都最终的位置,假设首都最终在x位置,那么所需要的花费就是:
b(c[1]-c[0])+a(c[1]-c[0])+b(c[2]-c[1])+a(c[2]-c[1])+…+b(c[x-1]-c[x-2])+a(c[x-1]-c[x-2])+b(c[x]-c[x-1])+a(c[x]-c[x-1])+…+b(c[n-1]-c[n-2])+b(c[n]-c[n-1])
整理的:
A=(a+b)(c[x]-c[0]),B=b*( ∑ i = x + 1 n c [ i ] − ( n − x ) ∗ c [ x ] ) \sum_{i=x+1}^n{c[i] - (n-x)*c[x])} i=x+1nc[i](nx)c[x])
假设x = x+1,那么A会增大(a+b)(c[x+1]-c[x]),而B会减小b(n-x)*(c[x+1]-c[x]),那么我们只需要考虑(a+b)和b(n-x)的大小了,如果A的增大值比B的减小值小,说明最有位置一定在x的后面。

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int N = 2e5 + 10;

int x[N];

void solve()
{
    int n, a, b; cin >> n >> a >> b;
    for (int i = 1; i <= n; i ++) cin >> x[i];

    int l = 0, r = n;
    while (l < r)
    {
        int mid = l + r >> 1;
        if ((n - mid) * b > (a + b)) l = mid + 1;
        else r = mid;
    }
    int ans = (x[l] - x[0]) * (a + b);
    for (int i = l + 1; i <= n; i ++)
        ans += b * (x[i] - x[l]);

    cout << ans << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);

    int t; cin >> t;
    while (t --) solve();

    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值