A.Maximum Subrectangle(赛时完成)
题意:求满足矩阵权值和 <= x ,且矩阵面积最大
思路:矩阵权值和 = 横区间和 * 纵区间和
预处理每个长度的最小区间和,对于每个长度的横区间和,二分查找最长符合条件纵区间和,对所有计算结果取max
#include<stdio.h> #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 100; const int inf = 0x3f3f3f3f; ll arr[maxn]; ll brr[maxn]; ll la[maxn], lb[maxn]; int main() { ll n, m ,x; scanf("%lld %lld", &n, &m); arr[0] = brr[0] = 0; memset(la, inf, sizeof la); memset(lb, inf, sizeof lb); for (int i = 1; i <= n; ++i) { scanf("%lld", &arr[i]); arr[i] = arr[i] + arr[i - 1]; } for (int i = 1; i <= n; ++i) { for (int j = i; j <= n; ++j) { la[j - i + 1] = min(la[j - i + 1], arr[j] - arr[i - 1]); } } for (int i = 1; i <= m; ++i) { scanf("%lld", &brr[i]); brr[i] = brr[i] + brr[i - 1]; } scanf("%lld", &x); for (int i = 1; i <= m; ++i) { for (int j = i; j <= m; ++j) { lb[j - i + 1] = min(lb[j - i + 1], brr[j] - brr[i - 1]); } } int ans = 0; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (la[i] * lb[j] <= x) ans = max(ans, i * j); } } printf("%d ", ans); return 0; }
B.Mouse Hunt(赛后完成)
题意:在房间中布置陷阱,询问无论老鼠从地出发都能被抓到的最小花费
思路:每个连通块都是n点n边出度为1,因此对于每个连通块必定有环,且连通块路径有且只有一条,dfs跑环,找到环上权值最小的点,计算所有连通块的环上权值最小点的和
#include<stdio.h> #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e5 + 100; const int inf = 0x3f3f3f3f; int val[maxn] ,to[maxn]; int vis[maxn] ,vis1[maxn]; int dfs(int rt) { if (vis[rt] != 0) return 0; vis1[rt]++; int ans = inf; if (vis1[rt] == 2) { if (to[rt] == rt) ans = val[rt]; ans = min(ans, val[rt]); for (int i = to[rt]; i != rt; i = to[i]) { ans = min(ans, val[i]); } return ans; } ans = min(ans, dfs(to[rt])); vis[rt] = 1; return ans == inf ? 0 : ans; } // n点n边且出度都为1 , 所以每个连通块必定有环 , 而且路径有且仅有一条 int main() { int n; memset(vis, 0, sizeof vis); memset(vis1, 0, sizeof vis1); scanf("%d", &n); int sum = 0; for (int i = 1; i <= n; ++i) scanf("%d", &val[i]); for (int i = 1; i <= n; ++i) scanf("%d", &to[i]); for (int i = 1; i <= n; ++i) { if (vis[i] == 0) { sum += dfs(i); } } printf("%d ", sum); return 0; }
C.Psychos in a Line(赛后完成)
题意:arr[i] > arr[i + 1] 第i个数字就可以把第i+1个数字消除掉,询问消除到没有数字可以消除所需要的步数
思路:用单调栈从后往前维护一个单调递增栈,用dp[i]来维护i消除所有能够消除的数字所需要的最大步数
#include<stdio.h> #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 100; const int inf = 0x3f3f3f3f; int arr[maxn]; int ans[maxn]; stack<int>s; int main() { int n; scanf("%d", &n); memset(ans, 0, sizeof ans); for (int i = 1; i <= n; ++i) scanf("%d", &arr[i]); for (int i = n; i >= 1; --i) { if (s.empty()) { s.push(i); ans[i] = 0; continue; } if (arr[s.top()] > arr[i]) { ans[i] = 0; s.push(i); } else { ans[i] = max(1, ans[s.top()]); // 第i个人肯定能杀死第s.top()个人 s.pop(); while (s.size() && arr[i] > arr[s.top()]) { ans[i] = max(ans[i] + 1, ans[s.top()]); s.pop(); } s.push(i); } } int val = 0; for (int i = 1; i <= n; ++i) { val = max(val, ans[i]); //printf("%d ", ans[i]); } //cout << endl; printf("%d ", val); return 0; }
D.Sequence Sorting(未完成)
E.Lucky Transformation(赛时完成)
题意:对于 i % 2 == 1 && arr[i] == 4 && arr[i + 1] == 7 ,arr[i + 1] = 4
i % 2 == 1 && arr[i] == 4 && arr[i + 1] == 4 ,arr[i + 1] = 7
思路:按题意模拟,考虑好特殊情况就行了
#include<stdio.h> #include<string.h> using namespace std; const int maxn = 1e5 + 100; int arr[maxn]; int main() { int n , k; scanf("%d %d", &n,&k); for (int i = 1; i <= n; ++i) scanf("%1d", &arr[i]); arr[0] = 0; for (int i = 1; i <= n; ++i) { if (k == 0) break; if (arr[i - 1] == 4 && arr[i] == 4 && arr[i + 1] == 7 && i % 2 == 0) { if (k % 2 == 1) arr[i] = 7; k = 0; break; } else if(arr[i - 1] == 4 && arr[i] == 7 && arr[i + 1] == 7 && i % 2 == 0) { if (k % 2 == 1) arr[i] = 4; k = 0; break; } else if (arr[i] == 4 && arr[i + 1] == 7 && i % 2 == 1) { arr[i + 1] = 4; k--; } else if (arr[i] == 4 && arr[i + 1] == 7 && i % 2 == 0) { arr[i] = 7; k--; } } for (int i = 1; i <= n; ++i) { printf("%d", arr[i]); } printf(" "); return 0; }
F.President's Path(未完成)