B - Pursuing the Happiness
题目大意
交换换一个字符串中的两个字符,使得结果不含子串 happiness ,如果无法完成则输出 NO ,否则输出 YES 以及交换的两个字符的下标。
思路 - 贪心
①如果这个字符串中子串
happiness
的个数大于
2
,则必定无法完成,输出
②如果这个字符串中的子串
happiness
的个数等于
2
,则交换第一个
③如果这个字符串中的子串
④如果这个字符串中不含子串
happiness
,此时要选择相同的字符交换,否则可能使得交换后的字符串含有
happiness
,如果不存在相同的字符,则必定不含有能够组成
happiness
的字符,选择最前的两个字符交换即可。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 200013;
const char HAPPINESS[] = {"happiness"};
char s[MAXN];
int cnt, fir[3], cnt_s, fir_s[3], len;
bool judge(int sta) {
for(int i = 0; i < 9; ++i) {
if(s[sta + i] != HAPPINESS[i]) {
return false;
}
}
return true;
}
void solve() {
cnt = 0;
cnt_s = 0;
len = strlen(s + 1);
for(int i = 1; i <= len; ++i) {
if(s[i] == 's' && cnt_s < 2) {
fir_s[cnt_s++] = i;
}
if(judge(i)) {
if(cnt == 2) {
printf("NO\n");
return ;
}
fir[cnt++] = i;
}
}
printf("YES\n");
if(cnt == 2) {
printf("%d %d\n", fir[0], fir[1] + 1);
}
else if(cnt == 1){
printf("%d %d\n", fir[0], fir[0] + 1);
}
else {
if(cnt_s == 2) {
printf("%d %d\n", fir_s[0], fir_s[1]);
}
else {
printf("1 2\n");
}
}
}
int main() {
while(1 == scanf("%s", s + 1)) {
solve();
}
return 0;
}
B. Urn with Balls
题目大意
一个壶中有
a
个红球、
思路 - 贪心
①
②
a+c>n && b+c<=m
,此时只要不违反红球的规则即可,答案为
n
;
③
④
a+c<=n && b+c>n
,此时只要不违反绿球的规则即可,答案为
m
。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long a, b, c, n, m, ans;
int main() {
while(5 == scanf("%I64d%I64d%I64d%I64d%I64d", &a, &b, &c, &n, &m)) {
if(a + c <= n && b + c <= m) {
printf("%I64d\n", a + b + c);
}
else if(a + c > n) {
printf("%I64d\n", b + c > m ? min(n, m) : n);
}
else { //a + c <= n && b + c > m
printf("%I64d\n", m);
}
}
return 0;
}
D. Jumps
题目大意
一只青蛙在数轴上跳,但每次向左或向右只能跳固定的长度,有
思路 - 数学
这道题和最大不能组成的数类似,所以直接判断所有长度的最大公约数能否被
x
整除即可,如果能则能到达
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, x, gcd, a;
int main() {
while(2 == scanf("%d%d", &n, &x)) {
scanf("%d", &gcd);
for(int i = 1; i < n; ++i) {
scanf("%d", &a);
gcd = __gcd(gcd, a);
}
printf("%s\n", abs(x) % gcd == 0 ? "YES" : "NO");
}
return 0;
}
E. Bonuses and Teleports
题目大意
数轴上有
思路 - 贪心 && 二分
两个传送点之间的奖金有两种拿法:
①从右边的传送点出发,拿完所有的奖金,然后再回到右边的传送点;
②从左边的传送点出发,拿一部分奖金(可以不拿,也可以全部都拿),然后回到左边的传送点,再从右边的传送点出发,拿剩余的奖金,然后再回到右边的传送点。
取两个传送点之间的所有奖金走的最短距离,就是上面两种情况下结果的最小值。
找两个传送点之间的奖金可以通过二分。
为了方便,再在 −INF 处和 INF 处分别添加一个传送点。
总时间复杂度: O(max(nlogm,m))
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 200003;
const long long INF = 0x3f3f3f3f3f3f3f3f;
int n, m, pos;
long long t[MAXN], b[MAXN];
int sta, des;
long long ans;
int binSearch(int l, int r, int key) {
int mid;
while(l <= r) {
mid = (l + r) >> 1;
if(b[mid] <= key) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
return l;
}
int main() {
while(2 == scanf("%d%d", &n, &m)) {
t[0] = -INF;
t[n + 1] = INF;
for(int i = 1; i <= n; ++i) {
scanf("%I64d", t + i);
}
for(int i = 0; i < m; ++i) {
scanf("%I64d", b + i);
}
b[m] = INF + 1;
sta = 0;
ans = 0;
for(int i = 0; i <= n; ++i) {
des = binSearch(sta, m, t[i + 1]) - 1;
if(sta <= des && b[des] <= t[i + 1]) {
long long tmp = min((b[des] - t[i]), (t[i + 1] - b[sta])) << 1;
while(sta < des) {
tmp = min(tmp, ((b[sta] - t[i]) + (t[i + 1] - b[sta + 1])) << 1);
++sta;
}
ans += min(tmp, t[i + 1] - t[i]);
sta = des + 1;
}
}
printf("%I64d\n", ans);
}
return 0;
G. I love Codeforces
题目大意
每个人初始有自己的昵称,然后按照时间顺序给出一些人的改昵称的规则,
a
思路 - 模拟
对每个人维护其前面有的
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 200003;
int n, m, a, b;
char name[MAXN][29];
int cnt[MAXN], ori[MAXN];
int main() {
while(1 == scanf("%d", &n)) {
for(int i = 1; i <= n; ++i) {
scanf("%s", name[i]);
cnt[i] = 0;
ori[i] = i;
}
scanf("%d", &m);
while(m-- > 0) {
scanf("%d%d", &a, &b);
cnt[a] = cnt[b] + 1;
ori[a] = ori[b];
}
for(int i = cnt[1]; i > 0; --i) {
printf("I_love_");
}
printf("%s\n", name[ori[1]]);
}
return 0;
}
H. Perfect Ban
题目大意
有一个 n × m 的矩阵,去掉一行和一列中的所有数,使得剩下的数中最大值最小,求行和列的下标?
思路 - 贪心
找到数组中最大的元素的一个位置(如果存在多个,且能够完全去掉,则通过枚举行和列可找到最优解,如果不能完全去掉,随便选择即可),枚举删除行(列),然后在找到剩下的数中的最大的数的一个位置,删除列(行),再找到剩下的数中最大的数 mx ,输出上面两种情况中 mx 最小的即可。
刚开始想得比较复杂,考虑了每一行和每一列的全部的数,结果 WA 在第 54 组数据。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1003;
int n, m;
int a[MAXN][MAXN];
bool isRow;
void getMax(int r, int c, int& rr, int& cc) {
int mx = 0;
for(int i = 1; i <= n; ++i) {
if(i != r) {
for(int j = 1; j <= m; ++j) {
if(j != c && mx < a[i][j]) {
rr = i;
cc = j;
mx = a[i][j];
}
}
}
}
}
int main() {
while(2 == scanf("%d%d", &n, &m)) {
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
scanf("%d", &a[i][j]);
}
}
int fir_r, fir_c;
getMax(0, 0, fir_r, fir_c);
int sec_r, sec_c;
getMax(fir_r, 0, sec_r, sec_c);
int tri_r, tri_c;
getMax(0, fir_c, tri_r, tri_c);
int r, c;
getMax(fir_r, sec_c, r, c);
int rr, cc;
getMax(tri_r, fir_c, rr, cc);
if(a[r][c] < a[rr][cc]) {
printf("%d %d\n", fir_r, sec_c);
}
else {
printf("%d %d\n", tri_r, fir_c);
}
}
return 0;
}
/*
3 3
12 10 9
10 11 11
9 10 10
*/
M. Last Man Standing
题目大意
有 n 个人,每个人可以向其他人开枪杀死他,现给出每个人杀的人数,求一个合法的击杀顺序。
思路 - 贪心
从杀人最少的开始设置两个指针
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 200003;
int n, a[MAXN], fir, sec;
long long sum;
int main() {
while(1 == scanf("%d", &n)) {
sum = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
sum += a[i];
}
if(sum >= n) {
printf("NO\n");
}
else {
printf("YES\n");
fir = sec = n;
while(a[fir] == 0) {
--fir;
}
while(fir > 0) {
printf("%d %d\n", fir, sec--);
if(--a[fir] == 0) {
--fir;
}
}
}
}
return 0;
}