题目传送门
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; }
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]); } }
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; }
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; }
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; }
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; }