X Samara Regional Intercollegiate Programming Contest

题目链接
题目
非官方代码

B - Pursuing the Happiness

题目大意

交换换一个字符串中的两个字符,使得结果不含子串 happiness ,如果无法完成则输出 NO ,否则输出 YES 以及交换的两个字符的下标。

思路 - 贪心

①如果这个字符串中子串 happiness 的个数大于 2 ,则必定无法完成,输出NO
②如果这个字符串中的子串 happiness 的个数等于 2 ,则交换第一个happiness h 和第二个happiness a
③如果这个字符串中的子串happiness的个数等于 1 ,则交换第一个happiness h a
④如果这个字符串中不含子串 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 个红球、b个绿球和 c 个颜色未知的球(红色或绿色),可以从这个壶中一次性拿出一些球,但要满足红球的个数不超过n,绿球的个数不超过 m ,求最多能拿多少球?

思路 - 贪心

a+c<=n && b+c<=m,此时取出全部球也不会违反要求,答案为 a+b+c
a+c>n && b+c<=m ,此时只要不违反红球的规则即可,答案为 n
a+c>n && b+c>n,此时两个规则都不能违反,所以只能取两个的较小值,答案为 min(n,m)
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

题目大意

一只青蛙在数轴上跳,但每次向左或向右只能跳固定的长度,有n中长度,分别为 ai ,青蛙初始在 0 ,请问青蛙能否跳到x

思路 - 数学

这道题和最大不能组成的数类似,所以直接判断所有长度的最大公约数能否被 x 整除即可,如果能则能到达x,否则不能到达 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

题目大意

数轴上有n个传送点,位置分别为 ti m 个奖金,位置分别为bi,一个人初始在 t1 ,求拿完所有的奖金在回到 t1 时所走的最短距离?

思路 - 贪心 && 二分

两个传送点之间的奖金有两种拿法:
①从右边的传送点出发,拿完所有的奖金,然后再回到右边的传送点;
②从左边的传送点出发,拿一部分奖金(可以不拿,也可以全部都拿),然后回到左边的传送点,再从右边的传送点出发,拿剩余的奖金,然后再回到右边的传送点。

取两个传送点之间的所有奖金走的最短距离,就是上面两种情况下结果的最小值。

找两个传送点之间的奖金可以通过二分。

为了方便,再在 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 b表示 a 的昵称将变为I_love_加上 b 当前的昵称,最后给出第一人的昵称。

思路 - 模拟

对每个人维护其前面有的I_love_的个数 cnt ,其最后的初始昵称的人 ori ,最后按照题意输出即可。

代码

#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 个人,每个人可以向其他人开枪杀死他,现给出每个人杀的人数,求一个合法的击杀顺序。

思路 - 贪心

从杀人最少的开始设置两个指针fir sec ,分别指向还能杀的人的数目最少的那个人 和 下一次会被杀的人,然后按照提议往前扫一遍即可。

代码

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值