牛客小白月赛14 :部分题目总结

 题目链接:https://ac.nowcoder.com/acm/contest/879#question

 官方题解:https://ac.nowcoder.com/discuss/189446?type=101&order=0&pos=1&page=1

A .简单计数

sol:考虑两个数组a和b,a[i]表示第i天在1号城市的方案数,b[i]表示第i天不在1号城市的方案数,可以得到如下dp方程式:

a[i] = b[i - 1];    b[i] = a[i - 1] * (n - 1) + b[i - 1] * (n - 2);

a[k]就是问题的答案。但是k比较大,不能暴力循环。可以将dp方程式转换成矩阵来利用矩阵快速幂求解

ps:n < 2的情况下上面的dp方程式就不对了。但是按照题目给出的maker.cpp,n和k的范围都在8e8到9e8之间;所以我就不得不吐槽一下这个示例1了,根本不满足数据范围。

  • 矩阵快速幂
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = 998244353;
    struct Mat {
        int mat[2][2];
        Mat() {memset(mat, 0, sizeof(mat));}
        friend Mat operator * (Mat a, Mat b) {
            Mat ans;
            for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
            for (int k = 0; k < 2; k++)
            ans.mat[i][j] = (ans.mat[i][j] + 1LL * a.mat[i][k] * b.mat[k][j]) % MOD;
            return ans;
        }
    };
    Mat mat_pow(Mat m, int k) {
        Mat ans;
        ans.mat[0][0] = ans.mat[1][1] = 1;
        while (k) {
            if (k & 1) ans = ans * m;
            m = m * m;
            k >>= 1;
        }
        return ans;
    }
    int main() {
        int n, k;
        scanf("%d%d", &n, &k);
        Mat m;
        m.mat[0][1] = 1;
        m.mat[1][0] = n - 1;
        m.mat[1][1] = n - 2;
        m = mat_pow(m, k);
        printf("%d\n", m.mat[0][0]);
        return 0;
    } 
    View Code

     

B .投硬币

 sol:把k次成功到n次成功的概率算出来,然后累加

  • 逆元
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e5 + 5;
    const int MOD = 998244353;
    int powa[MAXN], powb[MAXN], inv[MAXN]; 
    int ans, fac;
    int quick_pow(int n, int k) {
        int ans = 1;
        while (k) {
            if (k & 1) ans = 1LL * ans * n % MOD;
            n = 1LL * n * n % MOD;
            k >>= 1;
        }
        return ans;
    }
    int main() {
        // a 是成功的概率, b 是失败的概率 
        int n, k, a, b;
        scanf("%d%d%d", &n, &k, &a);
        b = (MOD + 1 - a) % MOD;
        powa[0] = powb[0] = fac = inv[0] = 1;
        for (int i = 1; i <= n; i++) {
            powa[i] = 1LL * a * powa[i - 1] % MOD;
            powb[i] = 1LL * b * powb[i - 1] % MOD;
            fac = 1LL * fac * i % MOD; 
        }
        inv[n] = quick_pow(fac, MOD - 2);
        // 线性地推阶乘逆元 
        for (int i = n - 1; i > 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MOD;
        for (int i = k; i <= n; i++) {
            int p = 1LL * powa[i] * powb[n - i] % MOD;
            // 这个c就是排列组合数,C(n, i); 
            int c = 1LL * fac * inv[n - i] % MOD * inv[i] % MOD;
            ans = (ans + 1LL * p * c) % MOD;
        }
        printf("%d\n", ans);
        return 0;
    }
    View Code

    第一次在比赛中运用逆元解出题目,而且比赛结束后又优化了代码,成功提交了目前为止本题最快代码。学习了线性递推阶乘的逆元。

C .植树造林

  sol:到所有树的最远距离最小的树一定是最中间的树。所以,如果n为奇数,最中间的树有一棵,否则有两棵。

  • 贪心水题
    #include "bits/stdc++.h"
    using namespace std;
    int main() {
        int n;
        scanf("%d", &n);
        puts(n & 1 ? "1" : "2");
        return 0;
    }
    View Code

     

D .签到提I

sol:排个序就完事了

  • 排序
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e5 + 5;
    int arr[MAXN];
    int main() {
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++)
            scanf("%d", &arr[i]);
        sort(arr + 1, arr + 1 + n);
        printf("%d\n", arr[k]);
        return 0;
    }
    View Code

    作为签到题,这题确实很水。不过如果把n的范围加到1e7,那么普通sort就要超时了。可以用堆排或手写的针对第k小的快排来完成。

G .many sum

sol:模拟素数筛的方法来求出b数组,然后把b数组异或起来得到答案

  • 素数筛的思路
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 2e6 + 5;
    int a[MAXN], b[MAXN];
    int n, MOD, ans;
    int main() {
        scanf("%d%d%d", &n, &a[1], &MOD);
        for (int i = 1; i <= n; i++) {
            for (int j = i; j <= n; j += i)
                b[j] = b[j] + a[i];
            a[i + 1] = (a[i] + 7 * i + 7) % MOD;
            ans ^= b[i];
        }
        printf("%d\n", ans);
        return 0;
    }
    View Code

    AB两道难的我做出来了,这题简单的比赛还没做出来。完全不知道d|i是什么意思,后来素数筛又算错了复杂度以为要超时。还是要仔细啊。

转载于:https://www.cnblogs.com/Angel-Demon/p/10863900.html

你可能感兴趣的:(牛客小白月赛14 :部分题目总结)