Codeforces Round #794 (Div2) A~E题解
作者:互联网
https://codeforces.com/contest/1686
好久没写题了,写着玩玩,发现思维有所下滑
A题
题意:
给你\(n\)个数,每次操作可以选择\(n - 1\)个数,将这\(n - 1\)个数变成它们的平均值,问你能否在有限次操作内使得所有数相等。
思路:
看所有数的总和的平均数在序列里有没有就行了。
int a[N];
void solve() {
int n;
cin >> n;
int s = 0;
for(int i = 1 ; i <= n ; i ++) cin >> a[i], s += a[i];
bool flag = false;
if(s % n == 0) {
s /= n;
for(int i = 1 ; i <= n ; i ++)
if(a[i] == s) {
flag = true;
break;
}
}
if(flag) cout << "YES\n";
else cout << "NO\n";
}
B题
题意:
给你一个数组,问你最多能把这个数组划分成多少个连续的奇数子数组
奇数数组是指这个数据的逆序对数目为奇数
思路:
为了使段数更多,每段区间当然是越短越好。因此直接贪心,每次出现一个递减的数就截断。
int a[N];
void solve() {
int n;
cin >> n;
for(int i = 1 ; i <= n ; i ++) cin >> a[i];
int cnt = 0;
int now = 0;
for(int i = 1 ; i <= n ; i ++) {
if(a[i] >= now) now = a[i];
else {
cnt ++;
now = 0;
}
}
cout << cnt << "\n";
}
C题
题意:
给你一个数组,把它当做环,问你能否通过随意排序使得这个环满足每个数要么比相邻的数都大,要么比相邻数都小。
思路:
首先,\(n\)为奇数肯定不行,因为首尾会矛盾。
要构造这种锯齿状,我们只需要排序后,奇偶位置交替放大的和小的数就行,然后检验即可。
int a[N];
int b[N];
void solve() {
int n;
cin >> n;
for(int i = 1 ; i <= n ; i ++) cin >> a[i];
if(n & 1) cout << "NO\n";
else {
sort(a + 1, a + n + 1);
int l = 1, r = n / 2 + 1;
int now = 1;
for(int i = 0 ; i < n / 2 ; i ++){
b[now ++] = a[l + i];
b[now ++] = a[r + i];
}
bool flag = true;
for(int i = 1 ; i <= n ; i ++) {
int l, r;
l = i - 1, r = i + 1;
if(l == 0) l = n;
if(r == n + 1) r = 1;
if((b[i] > b[l] && b[i] > b[r]) ||
(b[i] < b[l] && b[i] < b[r])) continue;
else {
flag = false;
break;
}
}
if(flag) {
cout << "YES\n";
for(int i = 1 ; i <= n ; i ++) cout << b[i] << " ";
cout << "\n";
}
else cout << "NO\n";
}
}
D题
题意:
给你四种基串 A, B, AB, BA的数目,和一个目标串S,问你能否通过基串任意顺序组合得到目标串S。
思路:
首先看看目标串和所给基串的A,B字符数目是否相等,不相等直接\(NO\)
假如我们能把AB和BA串在目标串S的填充好,那么剩下的位置是确定的,因此我们只需要考虑AB和BA串怎么放就行。
按照相邻不同的规则对目标串进行拆分,我们可以得到如下四种串
1.ABAB
2.BABA
3.ABABA
4.BABAB
显然,3号串在去除1个A后,可以由两个AB或者两个BA组成,4号串类似。
而1号和2号串则分别由两个AB、BA组成。
很容易发现ABAB串也可以转化成由BA构成,但是会损失两个字符,即 A BA B。
我们先将1号和2号串按照各自基串填充,然后用3、4号串对应去补充不足。
在此操作后,如果还有AB或BA串数目有缺失,那么考虑另一种串可能有多。
这个时候我们采取转化,将多的那一种串尽可能转化成另一种,注意一次转化整个连续串。
因为转化是有损失的,因此我们优先转化长度大的,这样才是最优的。
void solve() {
int a, b, ab, ba;
cin >> a >> b >> ab >> ba;
string s;
cin >> s;
// a + c + d b + c + d
int A = 0, B = 0;
for(int i = 0 ; i < s.size() ; i ++)
if(s[i] == 'A') A ++;
else B ++;
if(A != a + ab + ba || B != b + ab + ba) {
cout << "NO\n";
return;
}
int cab, cba, both;
cab = cba = both = 0;
int st = 0;
vector<int> AB, BA;
for(int i = 0 ; i <= s.size() ; i ++) {
if(i == s.size() || (i > 0 && s[i] == s[i - 1])) { // 遇到相同的字母
int len = i - st;
if(len & 1) both += len / 2;
else {
if(s[st] == 'A') cab += len / 2, AB.push_back(len / 2);
else cba += len / 2, BA.push_back(len / 2);
}
st = i;
}
}
int sum = cab + cba + both;
if(sum < ab + ba) {
cout << "NO\n";
return;
}
if(cab < ab){
int d = min(both, ab - cab);
cab += d;
both -= d;
}
if(cba < ba) {
int d = min(both, ba - cba);
cba += d;
both -= d;
}
sort(AB.begin(), AB.end(), greater<int>());
sort(BA.begin(), BA.end(), greater<int>());
for(int i = 0 ; i < AB.size() ; i ++) {
if(cab - 2 < ab) break;
int now = AB[i];
int d = min(cab - ab, now);
cba += d - 1;
cab -= d;
}
for(int i = 0 ; i < BA.size() ; i ++) {
if(cba - 2 < ba) break;
int now = BA[i];
int d = min(cba - ba, now);
cab += d - 1;
cba -= d;
}
if(cab >= ab && cba >= ba) cout << "YES\n";
else cout << "NO\n";
}
E题
题意:
给你一个括号串,每次操作可以选择任意一段串翻转,问你最少操作多少次使得整个括号串合法。
思路:
我们用\(1\)表示\((\),用\(-1\)表示\()\),用sum表示它们的前缀和,如果括号串合法,当且仅当对任意的i都有 \(sum[i] >= 0\)
我们找到数组中的最大\(sum[pos]\),那么我们翻转\([1, pos]\)和\([pos + 1, n]\)一定会满足条件。
因为如果翻转之后,\([1, pos]\)出现了\(sum[i] < 0\),那么\(sum[pos]\)将不会是最大前缀和,因为我们抛弃原来的\([i, pos]\)的数可以使得sum更大。
同理,区间\([pos + 1, n]\)也可以类似证明。
所以我们最多操作\(2\)次,那么考虑什么时候操作\(1\)次和\(0\)次。
显然当原串就合法就是0次。
假设区间\([l, r]\)是覆盖所有\(sum < 0\)的最小区间,那么:
如果r后面有更多的\((\)那么r应该贪心的往右边延申。也就是找到最大的\(sum[i]\)位置。
对于l,如果l左边有\()\)那么应该贪心的尽量往左边延申。也就是找到最小的\(rsum[i]\)的位置(从后往前的前缀和)。
这样我们就翻转贪心过后的\([l, r]\),如果检验合法,那么就一定可以一次翻转,否则就需要两次。
int a[N];
int sum[N], rsum[N];
char s[N];
int n;
bool check() {
for(int i = 1 ; i <= n ; i ++){
sum[i] = sum[i - 1] + a[i];
if(sum[i] < 0) return false;
}
return true;
}
void solve() {
cin >> n;
cin >> (s + 1);
n *= 2;
for(int i = 1 ; i <= n ; i ++){
if(s[i] == '(') a[i] = 1;
else a[i] = -1;
sum[i] = sum[i - 1] + a[i];
}
for(int i = n ; i >= 1 ; i --)
rsum[i] = rsum[i + 1] + a[i];
if(check()) {
cout << "0\n";
return;
}
int minv = n + 1, maxv = 0, pos = 1;
for(int i = 1 ; i <= n ; i ++) {
if(sum[i] < 0) {
minv = min(minv, i);
maxv = max(maxv, i);
}
if(sum[pos] < sum[i]) pos = i;
}
int l = minv, r = maxv;
for(int i = maxv + 1 ; i <= n ; i ++)
if(sum[r] < sum[i]) r = i;
for(int i = minv - 1 ; i >= 1 ; i --)
if(rsum[l] > rsum[i]) l = i;
reverse(a + l, a + r + 1);
if(check()) {
cout << 1 << "\n";
cout << l << " " << r << "\n";
return;
}
cout << 2 << "\n";
cout << 1 << " " << pos << "\n";
cout << pos + 1 << " " << n << "\n";
}
标签:794,BA,int,题解,sum,Codeforces,AB,now,cout 来源: https://www.cnblogs.com/luoyicong/p/16339480.html