Educational Codeforces Round 90 (Rated for Div. 2)
A - Donut Shops
void TestCase() {
ll a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
if(a > c) {
printf("-1 1\n");
return;
} else if(a == c) {
printf("-1 %lld\n", b);
return;
} else {
if(a * b <= c) {
printf("1 -1\n");
return;
} else {
printf("1 %lld\n", b);
return;
}
}
}
B - 01 Game
容易注意到,只要'0'和'1'的其中一种还没用完,都是始终可以操作的。所以就是判断一下距离用完其中一种需要的步数的奇偶性。
char s[20005];
void TestCase() {
scanf("%s", s + 1);
int n = strlen(s + 1);
int cnt0 = 0, cnt1 = 0;
for(int i = 1; i <= n; ++i) {
if(s[i] == '0')
++cnt0;
else
++cnt1;
}
if(min(cnt0, cnt1) % 2 == 1)
puts("DA");
else
puts("NET");
return;
}
C - Pluses and Minuses
题意:给一个串,串里面只有'+'和'-',执行下面的伪代码,求res的值。
res = 0
for init = 0 to inf
cur = init
ok = true
for i = 1 to |s|
res = res + 1
if s[i] == '+'
cur = cur + 1
else
cur = cur - 1
if cur < 0
ok = false
break
if ok
break
题解:容易知道随着 init 的增大每次 break 会越来越晚, break 的时候就是第一次使得 init + prefix < 0 的位置,最后当 init 超过了最小的 prefix 就会保持 ok 为 true 然后结束程序。所以有个简单的想法就是每次二分找第一个使得 init + prefix < 0 的位置。
char s[1000005];
int prefix[1000005];
int prefixmin[1000005];
void TestCase() {
scanf("%s", s + 1);
int n = strlen(s + 1);
for(int i = 1; i <= n; ++i) {
prefix[i] = prefix[i - 1];
if(s[i] == '+')
++prefix[i];
else
--prefix[i];
}
prefixmin[1] = prefix[1];
for(int i = 2; i <= n; ++i)
prefixmin[i] = min(prefixmin[i - 1], prefix[i]);
ll res = 0;
for(int init = 0;; ++init) {
int L = 1, R = n, ans = -1;
while(1) {
int M = (L + R) >> 1;
if(L == M) {
if(prefixmin[L] + init < 0) {
ans = L;
break;
} else if(prefixmin[R] + init < 0) {
ans = R;
break;
} else
break;
}
if(prefixmin[M] + init < 0)
R = M;
else
L = M + 1;
}
if(ans == -1) {
res += n;
break;
} else
res += ans;
}
printf("%lld\n", res);
return;
}
事实上也可以当每次 cur < 0 的时候(也就是 cur = -1 的时候)把 cur 重置为 0 并统计现在的贡献(其实就是当前的下标),因为下一次 init 增加了之后,到这个位置 cur 就会 cur = 0 ,所以可以这样转化。
D - Maximum Sum on Even Positions
题意:给一个数组,可以选择其中一个子数组翻转至多一次,求翻转后最大的“所有奇数位置的数的和”。
题解:很明显翻转的子数组必须长度为偶数才有用,这个看起来有点像用个前缀和搞搞就行了。具体来说就是枚举每个位置作为子数组的右端点,然后找一个位置作为左端点,要使得这个区间里的偶数位置和奇数位置的差异最大。
int n;
int a[200005];
void TestCase() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
ll sumodd = 0, sumeven = 0;
for(int i = 1; i <= n; ++i) {
if(i % 2 == 1)
sumodd += a[i];
else
sumeven += a[i];
}
ll ans = sumodd;
sumodd = 0, sumeven = 0;
ll maxdif = 0, maxtmp = 0;
for(int i = 1; i <= n; ++i) {
if(i % 2 == 1)
sumodd += a[i];
else {
sumeven += a[i];
ll tmp = sumeven - sumodd + maxdif;
maxtmp = max(maxtmp, tmp);
maxdif = max(maxdif, sumodd - sumeven);
}
}
sumodd = 0, sumeven = 0;
maxdif = 0;
for(int i = 1; i <= n; ++i) {
if(i % 2 == 1) {
sumodd += a[i];
ll tmp = sumeven - sumodd + maxdif;
maxtmp = max(maxtmp, tmp);
maxdif = max(maxdif, sumodd - sumeven);
} else
sumeven += a[i];
}
ans += maxtmp;
printf("%lld\n", ans);
return;
}