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]−(n−x)∗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;
}