新生赛题解

A 获得自由?

题解:判断奇偶即可

#include<stdio.h>

int main() {
    int n; scanf("%d", &n);
    if (n % 2 == 1) printf("YES\n");
    else printf("NO\n");
    return 0;
}

B 盖瓦

题解:从结尾的覆盖方案考虑,要么是一个竖着的多骨诺米牌占用一竖列,要么是两个横着的多骨诺米牌占用两行两列,所以可推出公式 f(n) = f(n-1) + f(n-2)

#include<stdio.h>

int a[30], i;

int main() {
    a[1] = 1, a[2] = 2;
    for(i = 3; i <= 20; ++ i) {
        a[i] = a[i-1] + a[i-2];
    }

    int T; scanf("%d", &T);
    while(T --) {
        int n; scanf("%d", &n);
        printf("%d\n", a[n]);
    }
    return 0;
}

C 平衡区间(削弱版)

题解:先记录前缀和(差分可以比较一个区间内x,y的个数),直接暴力枚举区间即可。

#include<stdio.h>

int a[3001], prex[3001], prey[3001];

int main() {
    int n, i, j; scanf("%d", &n);
    for(i = 1; i <= n; ++ i) {
        scanf("%d", &a[i]);
    }
    int x, y; scanf("%d%d", &x, &y);

    for(i = 1; i <= n; ++ i) {
        prex[i] = prex[i-1] + (a[i] == x);
        prey[i] = prey[i-1] + (a[i] == y);
    }
    int l, r, ans = 0;
    for(l = 1; l <= n; ++ l) {
        for(r = l; r <= n; ++ r) {
            if (prex[r] - prex[l-1] == prey[r] - prey[l-1]) {
                if (r - l + 1 > ans) ans = r - l + 1;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

D 石子游戏

题解:先得到两颗石子的差值 d,因为石子移动的步数是 \(2^{i}(i >= 1)\),所以若 d 为奇数,则无解。再回来看石子的移动步数(2,4,8,16 -> 10, 100, 1000, 10000),同样的差值 d 也能分成一个二进制(不妨为 110011010),可以看出移动左边石子差值对应位置 -1,移动右边石子差值对应位置 +1,所以我们不用考虑位上为 0 的位置,而对于位上为 1 的位置进行分类讨论(移动左边石子,或着移动右边石子)即爆搜。

#include<stdio.h>
#include<math.h>

int dfs(int d, int k) {
    if (d == 0) return 1;
    if (k == 0) return 0;

    if (d % 2 == 1) {
        if (dfs((d-1)/2, k-1)) return 1;
        if (dfs((d+1)/2, k-1)) return 1;
    }
    else if (dfs(d/2, k)) return 1;
    return 0;
}

int main() {
    int x, y, k; scanf("%d%d%d", &x, &y, &k);
    if (abs(x-y) % 2 == 0 && dfs(abs(x-y)/2, k)) printf("YES\n");
    else printf("NO\n");
    return 0;
}

E 平衡区间

题解:遍历数组,维护一个关于 x, y 个数的差值,若出现差值重复的情况,则现在的位置与该差值第一次出现的位置的后一位所包含的区间为平衡区间。

#include<stdio.h>

int a[1000001], pos[2000001];

int main() {
    int n, i; scanf("%d", &n);
    for(i = 1; i <= n; ++ i) {
        scanf("%d", &a[i]);
    }
    int x, y; scanf("%d%d", &x, &y);

    for(i = 0; i <= 2*n; ++ i) {
        pos[i] = -1;
    }
    pos[n] = 0;

    int cnt = n, ans = 0;
    for(i = 1; i <= n; ++ i) {
        if (a[i] == x) cnt ++;
        if (a[i] == y) cnt --;
        if (pos[cnt] == -1) pos[cnt] = i;
        else if (ans < i - pos[cnt]) ans = i - pos[cnt];
    }
    printf("%d\n", ans);
    return 0;
}

F 数字钟

题解:全部化为秒,然后再转化为标准时间。

#include<stdio.h>

int main() {
    int x, y, t; scanf("%d%d%d", &x, &y, &t);
    int sum = (x * 3600 + y * 60 + t) % (3600*24);
    printf("%02d:%02d:%02d", sum / 3600, (sum % 3600) / 60, sum % 60);
    return 0;
}

G 放烟花

题解:把烟花点燃时间从大到小排序,枚举 min(m, n-1) 根引线,若第 i 根引线连接时间低于第 i 箱烟花点燃时间,则连接引线,否则没有必要连接后面的引线。

#include<stdio.h>

int a[1001];

int main() {
    int n, m, i, j; scanf("%d%d", &n, &m);
    for(i = 1; i <= n; ++ i) {
        scanf("%d", &a[i]);
    }
    for(i = 1; i <= n; ++ i) {
        for(j = i+1; j <= n; ++ j) {
            if (a[i] < a[j]) {
                int c = a[i];
                a[i] = a[j];
                a[j] = c;
            }
        }
    }

    int ans = 0;
    for(i = 1; i <= n; ++ i) {
        ans += a[i];
    }
    for(i = 1; i <= m; ++ i) {
        if (i == n) break;
        if (a[i] > 11 * i) ans -= a[i] - 11*i;
        else break;
    }
    printf("%d", ans);
    return 0;
}

H 完美序列

题解:直接枚举数组,若 (a[i] % a[i-1] != 0 && a[i-1] % a[i] != 0),则将 a[i] = 1,并统计更改次数。

#include<stdio.h>

int a[1001];

int main() {
    int n, i; scanf("%d", &n);
    int ans = 0; a[0] = 1;
    for(i = 1; i <= n; ++ i) {
        scanf("%d", &a[i]);
        if (a[i] % a[i-1] != 0 && a[i-1] % a[i] != 0) a[i] = 1, ans ++;
    }
    printf("%d", ans);
    return 0;
}
posted @ 2020-12-24 17:06  Daowuu  阅读(205)  评论(0编辑  收藏  举报