2019计蒜之道初赛第三场题解

题目传送门

A .淘宝商品价格大PK

sol:枚举删除每一个数,然后求最大上升子序列。

  • 枚举
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 105;
    int arr[MAXN], n, ans;
    map<int, int>::iterator it;
    int getLIS(int k) {
        map<int, int> mp;
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            if (i == k) continue;
            int mx = 0;
            for (it = mp.begin(); it != mp.end() && it->first < arr[i]; it++) 
                if (it->second > mx) mx = it->second;
            mp[arr[i]] = mx + 1;
            ans = max(ans, mp[arr[i]]);
        }
        return ans;
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) 
            scanf("%d", &arr[i]);
        int k = getLIS(0);
        for (int i = 1; i <= n; i++) 
            if (getLIS(i) < k) ans ++;
        printf("%d\n", ans);
        return 0;
    }
    View Code

B .阿里巴巴协助征战SARS(简单)

sol:

dp[i][1]表示长度为i而且'A'的个数为奇数'C'的个数为偶数的情况;dp[i][1] = dp[i - 1][1] * 2 + dp[i - 1][3] + dp[i - 1][4];

dp[i][2]表示长度为i而且'A'的个数为偶数'C'的个数为奇数的情况;dp[i][2] = dp[i - 1][2] * 2 + dp[i - 1][3] + dp[i - 1][4];

dp[i][3]表示长度为i而且'A'的个数为奇数'C'的个数为奇数的情况;dp[i][3] = dp[i - 1][3] * 2 + dp[i - 1][1] + dp[i - 1][2];

dp[i][4]表示长度为i而且'A'的个数为偶数'C'的个数为偶数的情况;dp[i][4] = dp[i - 1][4] * 2 + dp[i - 1][1] + dp[i - 1][2];

  • 动态规划
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = 1e9 + 7;
    const int MAXN = 1005;
    int dp[MAXN][5];
    void init() {
        dp[0][4] = 1;
        for (int i = 1; i <= 1000; i++) {
            dp[i][1] = (dp[i - 1][1] * 2LL + dp[i - 1][3] + dp[i - 1][4]) % MOD;
            dp[i][2] = (dp[i - 1][2] * 2LL + dp[i - 1][3] + dp[i - 1][4]) % MOD;
            dp[i][3] = (dp[i - 1][3] * 2LL + dp[i - 1][1] + dp[i - 1][2]) % MOD;
            dp[i][4] = (dp[i - 1][4] * 2LL + dp[i - 1][1] + dp[i - 1][2]) % MOD;
        }
    }
    int main() {
        init(); int n;
        while (scanf("%d", &n) && n)
        {
            printf("%d\n", dp[n][4]);
        }
    }
    View Code

C .阿里巴巴协助征战SARS(中等)

sol1:观察上一题的状态转移方程式发现可以转化成矩阵快速幂来求解

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

sol2:官方题解中是用普通快速幂的公式来解的,不过需要一系列数学转化。我看不懂。结论是dp[n][4] = (2n-1) * (2n-1+1)

  • 快速幂
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = 1e9 + 7;
    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() {
        int k;
        while (scanf("%d", &k) && k) {
            int p = quick_pow(2, k - 1);
            printf("%d\n", 1LL * p * (p + 1) % MOD);
        }
        return 0;
    }
    View Code

D .阿里巴巴协助征战SARS(困难)

sol1:在群里看到一种解法说是十进制快速幂,对着这个名字想了一下就知道怎么写了,但是这种快速幂用到矩阵里就超时。应该是矩阵的常数比较大吧。

  • 十进制快速幂 + 逆元
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = 1e9 + 7;
    const int MAXN = 1e5 + 5;
    char k[MAXN];
    int quick_pow_2(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 quick_pow_10(int n, char* k) {
        int ans = 1;
        int l = strlen(k);
        for (int i = l - 1; i >= 0; i--) {
            ans = 1LL * ans * quick_pow_2(n, k[i] ^ '0') % MOD;
            n = quick_pow_2(n, 10);
        }
        return ans;
    }
    int main() {
        while (scanf("%s", k)) {
            if (strlen(k) == 1 && k[0] == '0') break;
            int p = quick_pow_10(2, k);
            // 因为高精度减法麻烦,而且上面已经写好了快速幂,所以就用逆元来解决多乘进去的那个2; 
            p = 1LL * p * quick_pow_2(2, MOD - 2) % MOD;
            printf("%d\n", 1LL * p * (p + 1) % MOD);
        }
        return 0;
    }
    View Code

sol2:可以用费马小定理来解决高精度问题。写逆元的时候一直在用费马小定理,但是放外面就想不到了。这种解法用矩阵快速幂也不会超时了。

  • 费马小定理
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = 1e9 + 7;
    const int MAXN = 1e5 + 5; 
    struct Mat {
        int mat[5][5];
        Mat() {memset(mat, 0, sizeof(mat));}
        friend Mat operator * (Mat a, Mat b) {
            Mat c;
            for (int k = 1; k <= 4; k++)
            for (int i = 1; i <= 4; i++)
            for (int j = 1; j <= 4; j++)
            c.mat[i][j] = (c.mat[i][j] + 1LL * a.mat[i][k] * b.mat[k][j]) % MOD;
            return c;
        }
    };
    Mat mat_pow(Mat n, int k) {
        Mat ans;
        for (int i = 1; i <= 4; i++) ans.mat[i][i] = 1;
        while (k) {
            if (k & 1) ans = ans * n;
            n = n * n;
            k >>= 1;
        }
        return ans;
    }
    char s[MAXN];
    int main() {
        while (scanf("%s", &s)) {
            if (strlen(s) == 1 && s[0] == '0') break;
            Mat m; int k = 0;
            for (int i = 0; s[i]; i++) k = (k * 10LL + s[i] - '0') % (MOD - 1);
            m.mat[1][1] = m.mat[2][2] = m.mat[3][3] = m.mat[4][4] = 2;
            m.mat[1][3] = m.mat[1][4] = m.mat[2][3] = m.mat[2][4] = 1;
            m.mat[3][1] = m.mat[4][1] = m.mat[3][2] = m.mat[4][2] = 1;
            m = mat_pow(m, k); 
            printf("%d\n", m.mat[4][4]);
        }
        return 0;
    }
    View Code

猜你喜欢

转载自www.cnblogs.com/Angel-Demon/p/10963152.html