• 2020牛客寒假算法基础集训营二 题解


    AB水题就不说了

    C .算概率 

    其实也是水题,n^2的概率dp,但是我场上没看这道题(雾

    简单的状态转移方程dp[n][m]记录前n道题做出m道的概率

    dp[n][m] = dp[n - 1][m - 1] * p[n] + dp[n - 1][m] * (1 - p[n]);
    //dp[n][m] = dp[n - 1][m - 1] * p[n] + dp[n - 1][m] * (1 - p[n]);
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const int N = 2020;
    const ll MOD = 1e9 + 7;
    ll p[N], dp[N][N];
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &p[i]);
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            dp[i][0] = dp[i - 1][0] * (1 - p[i] + MOD) % MOD;
            for (int j = 1; j <= i; j++)
                dp[i][j] = (dp[i - 1][j - 1] * p[i] % MOD + dp[i - 1][j] * (1 - p[i] + MOD) % MOD) % MOD;
        }
        for (int i = 0; i <= n; i++)
            printf("%lld ", dp[n][i]);
        return 0;
    }

    D.数三角

    不难,但是我被坑了很久,刚开始是没有判断共线,直角各种各样的东西,后来还被EPS卡了,总之非常绝望。

    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int N = 510;
    int pos[N][2];
    const long double EPS = 1e-10;
    struct vector {
        long long x, y;
    };
     
    inline long long dis(int a, int b) {
        long long u = (pos[a][0] - pos[b][0]) * (pos[a][0] - pos[b][0]) + (pos[a][1] - pos[b][1]) * (pos[a][1] - pos[b][1]);
        return u;
    }
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%d %d", &pos[i][0], &pos[i][1]);
        int tot = 0;
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++)
                for (int k = j + 1; k < n; k++) {
                    long long ik = dis(i, k), jk = dis(j, k), ij = dis(i, j);
                    if (sqrt(ik) + sqrt(jk) - sqrt(ij) < EPS || sqrt(ik) + sqrt(ij) - sqrt(jk) < EPS || sqrt(jk) + sqrt(ij) - sqrt(ik) < EPS)  // 判断是否共线
                        continue;
                    vector a = {pos[k][0] - pos[i][0], pos[k][1] - pos[i][1]}; //用点积判断
                    vector b = {pos[k][0] - pos[j][0], pos[k][1] - pos[j][1]};
                    long double res = 1ll * a.x * b.x + 1ll * a.y * b.y;
                    if (res < 0) {
                        tot++;
                        continue;
                    }
                    if (res < EPS) //等于直角就没必要再考虑了,节省时间
                        continue;
                    a.x = pos[i][0] - pos[k][0]; a.y = pos[i][1] - pos[k][1];
                    b.x = pos[i][0] - pos[j][0]; b.y = pos[i][1] - pos[j][1];
                    res = 1ll * a.x * b.x + 1ll * a.y * b.y;
                    if (res < 0) {
                        tot++;
                        continue;
                    }
                    if (res < EPS)
                        continue;
                    a.x = pos[j][0] - pos[k][0]; a.y = pos[j][1] - pos[k][1];
                    b.x = pos[j][0] - pos[i][0]; b.y = pos[j][1] - pos[i][1];
                    res = 1ll * a.x * b.x + 1ll * a.y * b.y;
                    if (res < 0) {
                        tot++;
                        continue;
                    }
                }
        printf("%d", tot);
        return 0;
    }

    F.拿物品

    同类型贪心的明明见过很多次了,但是再次碰到我又崩了qwq,每次这种题都是排序乱搞就出来了,这个也不例外。

    你可以想一想,你拿了一个,相当于你多了一个,对方少了一个,所以两者加起来排序就可以了

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 2 * 1e5 + 10;
    typedef pair <int, int> P;
    P a[N];
    #define f first
    #define s second
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i].f), a[i].s = i + 1;
        for (int i = 0; i < n; i++) {
            int k; scanf("%d", &k);
            a[i].f += k;
        }
        sort(a, a + n);
        for (int i = n - 1; i >= 0; i -= 2)
            printf("%d ", a[i].s);
        puts("");
        for (int i = n - 2; i >= 0; i -= 2)
            printf("%d ", a[i].s);
        return 0;
    }

    H.施魔法

    dp,dp的状态转移方程倒是挺好想的,但是我一开始就没有把这道题联系到DP上去,不过需要用前缀最小值优化一下

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 3 * 1e5 + 10;
    int a[N], d[N], pre[N];
    int main() {
        int n, k;
        scanf("%d %d", &n, &k);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        sort(a + 1, a + n + 1);
        for (int i = 1; i < k; i++)
            pre[i] = -a[1];
        d[k] = a[k] - a[1];
        pre[k] = d[k] - a[k + 1];
        for (int i = k + 1; i <= n; i++) {
            d[i] = pre[i - k] + a[i];
            pre[i] = min(pre[i - 1], d[i] - a[i + 1]);
        }
        printf("%d", d[n]);
        return 0;
    }
     
    // d[i] = min{d[i - k] - a[i - k + 1]} + a[i];

    I.建通道

    思维题,理解lowbit和xor的性质就能很好做。

    就是要注意一个问题,离散化的时候第一个单独处理,否则如果第一个是0容易误判

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 2 * 1e5 + 10;
    int v[N];
    int a[N];
    int cnt = 0;
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d", &v[i]);
        sort(v + 1, v + n + 1);
        a[++cnt] = v[1];
        for (int i = 2; i <= n; i++)
            if (v[i] != v[i - 1])
                a[++cnt] = v[i];
        int k = -1;
        for (int i = 0; i <= 31; i++) {
            bool flag1 = false, flag2 = false;
            for (int j = 1; j <= cnt; j++) {
                if ((1 << i) & a[j])
                    flag1 = true;
                else
                    flag2 = true;
                if (flag1 && flag2)
                    break;
            }
            if (flag1 && flag2) {
                k = i;
                break;
            }
        }
        long long ans = 1ll * (1 << k) * (cnt - 1);
        printf("%lld", ans);
        return 0;
    }

    J. 求函数

    线段树,就是合并的过程比较有趣

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define g(l, r)    (l + r | l != r)
    #define o g(l, r)
    #define ls g(l, mid)
    #define rs g(mid + 1, r)
    typedef long long ll;
    const ll MOD = 1e9 + 7;
    const int N = 2 * 1e5 + 10;
    ll k[N], b[N], sum1[N << 1], sum2[N << 1];
    int L, R;
    void build(int l, int r) {
        if (l == r) {
            sum1[o] = k[l] % MOD;
            sum2[o] = b[l] % MOD;
            return ;
        }
        int mid = l + r >> 1;
        build(l, mid);
        build(mid + 1, r);
        sum1[o] = sum1[ls] * sum1[rs] % MOD;
        sum2[o] = (sum2[ls] * sum1[rs] % MOD + sum2[rs]) % MOD;
    }
    
    void update(int l, int r, int p, ll kp, ll bp) {
        if (l == r) {
            sum1[o] = kp % MOD;
            sum2[o] = bp % MOD;
            return ;
        }
        int mid = l + r >> 1;
        if (p <= mid)    update(l, mid, p, kp, bp);
        else    update(mid + 1, r, p, kp, bp);
        sum1[o] = sum1[ls] * sum1[rs] % MOD;
        sum2[o] = (sum2[ls] * sum1[rs] % MOD + sum2[rs]) % MOD;
    }
    
    ll query1(int l, int r) {
        if (l >= L && r <= R) {
            return sum1[o];
        }
        int mid = l + r >> 1;
        ll ans = -1;
        if (mid >= L)    ans = query1(l, mid);
        if (mid < R) {
            if (ans == -1)
                ans = query1(mid + 1, r);
            else
                ans = query1(mid + 1, r) * ans % MOD;
        }
        return ans % MOD;
    }
    
    ll query2(int l, int r) {
        if (l >= L && r <= R)
            return sum2[o];
        int mid = l + r >> 1;
        ll ans = -1;
        if (mid >= L)    ans = query2(l, mid);
        if (mid < R) {
            if (ans == -1)
                ans = query2(mid + 1, r);
            else
                ans = (ans * query1(mid + 1, r) % MOD + query2(mid + 1, r)) % MOD;
        } 
        return ans % MOD;
    }
    
    int main() {
        int n, m;
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &k[i]);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &b[i]);
        build(1, n);
        while (m--) {
            int flag; scanf("%d", &flag);
            if (flag == 1) {
                int i; ll k, b;
                scanf("%d %lld %lld", &i, &k, &b);
                update(1, n, i, k, b);
            }
            else {
                scanf("%d %d", &L, &R);
                ll ans = (query1(1, n) + query2(1, n)) % MOD;
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    大学生自学网
    如何保证主从复制数据一致性
    CDN
    后端 线上 服务监控 与 报警 方案2
    利用 Gearman 实现系统错误报警功能
    增量部署和全量部署
    后端线上服务监控与报警方案
    简析TCP的三次握手与四次分手
    301 和 302 对 SEO 的影响
    Linux 查看负载
  • 原文地址:https://www.cnblogs.com/cminus/p/12305599.html
Copyright © 2020-2023  润新知