CF-637

题目传送门

A .Nastya and Rice

pro:问能否找出$n$个区间$[a - b, a + b]$内的数,满足和在区间$[c - d, c + d]$之内。

sol:最小的和是$n * (a - b)$,如果$n * (a - b) > c + d$,结果为"NO";最大的和是$n * (a + b)$,如果$n * (a + b) < c - d$,结果为"NO";剩下的情况结果都是"YES"。

  • 数学
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    
    inline int read() {
        int n = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-') f = -f;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            n = 10 * n + (c ^ '0');
            c = getchar();
        }
        return f * n;
    }
    int main() {
        int t = read();
        for (int i = 1; i <= t; i++) {
            int n = read(); bool ok = 1;
            int a = read(), b = read(), c = read(), d = read();
            if ((a + b) * n < (c - d)) ok = 0;
            if ((a - b) * n > (c + d)) ok = 0;
            puts(ok ? "Yes" : "No");
        }
        return 0;
    }
    View Code

     

B .Nastya and Door

pro:找出一个长度为k的区间,使得区间内峰的数量是最大的,若两个区间内峰的数量相同,认为左边的区间为大。区间的两端不是峰。最后输出区间内峰的数量+1和区间的左端点。

sol:前缀和求出$[1, i]$之间峰的个数,对于询问$[i, i + k - 1]$有多少峰,由于两端不认为是峰,所以结果为$cnt[i + k - 2] - cnt[i]$。

  • 前缀和
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 200010;
    int val[MAXN], cnt[MAXN];
    inline int read() {
        int n = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-') f = -f;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            n = 10 * n + (c ^ '0');
            c = getchar();
        }
        return f * n;
    }
    int main() {
        int t = read();
        while (t--) {
            int n = read(), k = read();
            for (int i = 1; i <= n; i++) val[i] = read();
            for (int i = 2; i < n; i++) {
                cnt[i] = (val[i] > val[i - 1] && val[i] > val[i + 1]);
                cnt[i] += cnt[i - 1];
            }
            int ans = 0, pos = 1;
            for (int i = 1; i + k - 1 <= n; i++) {
                if (cnt[i + k - 2] - cnt[i] > ans) {
                    ans = cnt[i + k - 2] - cnt[i];
                    pos = i;
                }
            }
            printf("%d %d\n", ans + 1, pos);
        }
        return 0;
    }
    View Code

     

C .Nastya and Strange Generator

pro:可以进行数次操作,每次操作选一个$i$,然后按顺序取出$[i, n]$之内还没被取出的数,问能否构造给定排列。

sol:扫描一下整个数组,要么$a[i] = a[i - 1] + 1$,要么$a[i]$为当前最小值。否则不可构造。做好做,题意是真的难懂。

  • 模拟
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 200010;
    int a[MAXN];
    inline int read() {
        int n = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-') f = -f;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            n = 10 * n + (c ^ '0');
            c = getchar();
        }
        return f * n;
    }
    int main() {
        int t = read();
        while (t--) {
            int n = read(); bool ok = 1;
            int k = a[1] = read();
            for (int i = 2; i <= n; i++) {
                a[i] = read();
                if (a[i] == a[i - 1] + 1) continue;
                if (a[i] >= k) ok = 0;
                else k = a[i];
            }
            puts(ok ? "Yes" : "No");
        }
        return 0;
    }
    View Code

     

D .Nastya and Scoreboard

pro:用一个$7$位二进制字符串表示一个电子数字,给出$n$个电子数字,这$n$个电子数字里有$m$根电子灯管本来该亮的但是没亮,求这$n$个电子数组组成的数最大是多少。允许前导零。

sol:先二进制压缩把字符串转成整型。然后用动态规划解决。$dp[i][j]$表示第$i$个电子数字到第$n$个电子数字一共有$j$根电子灯管该亮没亮的情况下,第$i$个电子数字的最大可能。

  • 动态规划
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 2010;
    inline int read() {
        int n = 0, f = 1; char c = getchar();
        while (c < '0' || c > '1') {
            if (c == '-') f = -f;
            c = getchar();
        }
        while (c >= '0' && c <= '1') {
            n = 2 * n + (c ^ '0');
            c = getchar();
        }
        return f * n;
    }
    int a[MAXN], d[] = {119, 18, 93, 91, 58, 107, 111, 82, 127, 123};
    int dp[MAXN][MAXN];
    int count(int i, int k) { // 把第i个数转成k需要点亮多少电子管
        if ((a[i] | d[k]) != d[k]) return -1;
        int p = d[k] - a[i], cnt = 0;
        while (p != 0) {
            cnt ++;
            p -= p & -p;
        }
        return cnt;
    }
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        memset(dp, -1, sizeof(dp));
        for (int i = 1; i <= n; i++) a[i] = read();
        for (int k = 0; k < 10; k++) {
            int cnt = count(n, k);
            if (cnt != -1) dp[n][cnt] = k;
        }
        for (int i = n - 1; i >= 1; i--) {
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k < 10; k++) {
                    int cnt = count(i, k);
                    if (cnt == -1) continue;
                    if (dp[i + 1][j - cnt] != -1) {
                        dp[i][j] = k;
                    }
                }
            }
        }
        if (dp[1][m] == -1) return 0 * puts("-1");
        for (int i = 1; i <= n; i++) {
            printf("%d", dp[i][m]);
            m -= count(i, dp[i][m]);
        }
        return 0;
    }
    View Code

     

posted @ 2020-04-24 16:06  Jathon-cnblogs  阅读(357)  评论(0编辑  收藏  举报