zoukankan      html  css  js  c++  java
  • 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
      ", 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
      ", 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
      ", 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
      ", 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
      ", 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
      ", m.mat[4][4]);
          }
          return 0;
      }
      View Code
  • 相关阅读:
    C++的精髓——代码复用、接口复用
    静态库和动态库的区别和win平台和linux平台代码实现
    windows工程总结
    预编译头文件stdafx.h-stdafx.cpp-stdafx.pch(pre-compile headfile)
    linux调用库的方式
    Window 32位 编程总结
    读Zepto源码之内部方法
    读Zepto源码之代码结构
    再谈 javascript 数组去重
    把axios封装为vue插件使用
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/10963152.html
Copyright © 2011-2022 走看看