A.Grandma Laura and Apples(Codeforces 632A)
大意
奶奶有若干个苹果,当她还剩奇数个苹果的时候会卖出一半的苹果(比如奶奶还剩
3
个苹果时会卖出
思路
不妨先顺着问题发生的顺序理一理思路。假设奶奶有
6
个苹果,那么第一次出售只能是
代码
#include <bits/stdc++.h>
using namespace std;
char s[10];
int n, p, a[50];
long long m, ans;
int main() {
scanf("%d%d", &n, &p);
for(int i = 0; i < n; i++) {
scanf("%s", s);
if(strlen(s) > 4) a[i] = 1;
else a[i] = 0;
}
for(int i = n - 1; i >= 0; i--) {
if(a[i]) m = (m + 5) << 1;
else m <<= 1;
ans += m / 2;
}
printf("%I64d\n", ans * p / 10);
return 0;
}
B. Alice, Bob, Two Teams(Codeforces 632B)
大意
有一个只含
A
和
思路
既然 Bob 能选择一个前缀或后缀进行翻转的话,那就枚举这个前缀或后缀进行翻转,然后更新最大值即可。注意,不能真的去暴力枚举,如果想枚举前缀 s[0...p] 的话,我们可以利用前一次枚举,即 s[0...p−1] 的结果。这是前缀和后缀的性质决定的。实现起来就是分别正向,反向扫描一次字符串,分别维护翻转后的前缀,后缀和。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
char s[maxn];
int n, p[maxn];
long long sum, tmp, ans;
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &p[i]);
}
scanf("%s", s);
sum = 0;
for(int i = 0; i < n; i++) {
if(s[i] == 'B') {
sum += p[i];
}
}
ans = tmp = sum;
for(int i = 0; i < n; i++) {
if(s[i] == 'A') {
tmp += p[i];
ans = max(ans, tmp);
}
else tmp -= p[i];
}
tmp = sum;
for(int i = n - 1; i >= 0; i--) {
if(s[i] == 'A') {
tmp += p[i];
ans = max(ans, tmp);
}
else tmp -= p[i];
}
printf("%I64d\n", ans);
return 0;
}
C.The Smallest String Concatenation(Codeforces 632C)
大意
有一个字符串集合,问将集合中的字符串首尾相连能够得到的字典序最小的字符串是什么。
思路
刚拿到这道题的时候,感觉应该是按照字典序排序,然后直接按照排序结果首尾相连。但是后来验证猜想的时候就出问题了。例如,有三个字符串:
x,xx,xxa
,若按照字典序来连接的话应该是
xxxxxa
,但是显然,
xxaxxx
的字典序更小。问题出在哪儿呢?如果字符串的长度都相同的话这样是没问题的,但若字符串长度不相同的话,像x这样短的字符串就会有更小的字典序,但它不见得应该排在更前面。怎么办呢?我们应该定义一个“更适合放在前面”的量,让这些字符串根据这个量来排序。显然,对于两个字符串而言,若
A+B
的字典序小于
B+A
,那么,
A
更适合放在
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 5;
int n;
string ans, s[maxn];
bool cmp(string a, string b) {
return a + b < b + a;
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
for(int i = 0; i < n; i++) {
cin >> s[i];
}
sort(s, s + n, cmp);
ans = "";
for(int i = 0; i < n; i++) {
ans = ans + s[i];
}
cout << ans << endl;
return 0;
}
D. Longest Subsequence(Codeforces 632D)
大意
有一个含
n
个数字的序列,求最长的满足以下性质的子序列:其所有元素的
思路
看见题中有
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int n, m, l, a[maxn], d[maxn];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
// 输入的同时维护d数组
if(a[i] <= m) d[a[i]]++;
}
// 逆序遍历d数组
for(int i = m; i >= 1; i--) {
// 枚举i的倍数
for(int j = 2 * i; j <= m; j += i) {
d[j] += d[i];
}
}
l = max_element(d + 1, d + m + 1) - d;
printf("%d %d\n", l, d[l]);
for(int i = 1; i <= n; i++) {
if(l % a[i] == 0) {
printf("%d ", i);
}
}
puts("");
return 0;
}
(其它题目略)