百度春招算法岗笔试,编程DP题(27%+36%),惨不忍睹。
两道题通过率分别是:27% + 36%,惨不忍睹啊。。
- 分别给两行正整数
和
,数组 A 和 B 的长度都是 n,一共有 m 个回合,每回合从数组 A 中取出一个数字,然后数组 A 的剩下每个数字
都减去
变成
,问
个回合后所有取出数字和最大是?数据范围
,
,
。
想法:只通过 27% 先把所有输入按照 B 数组从大到小排序,令表示从前
个数字中,经过
回合可以取出的最大数字和。则:
时间复杂度:。交上去报 RE 错误。。。搞不懂了。。。
另外一种(错误的)贪心的思路是每次取剩下所有数字中的最大值,通过率也是 27%。。。。。
#include <bits/stdc++.h> #define IOS ios_base::sync_with_stdio(0); cin.tie(0); using namespace std; typedef long long ll; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; const int N = 1100; int n, m; int A[N], B[N], dp[N][N], vis[N]; int greedy() { memset(vis, 0, sizeof(vis)); int ans = 0; for (int i = 0; i < m; ++i) { int find = -1, Max = -0x3f3f3f3f; for (int j = 0; j < n; ++j) if (!vis[j]) { if (A[j] > Max) { Max = A[j]; find = j; } } ans += A[find]; vis[find] = 1; for (int j = 0; j < n; ++j) if (!vis[j]) A[j] -= B[j]; } return ans; } struct Point { int a, b; bool operator < (const Point& rhs) const { return b > rhs.b ? true : a >= rhs.a; } } pt[N]; int solve() { for (int i = 0; i < n; ++i) { pt[i].a = A[i]; pt[i].b = B[i]; } sort(pt, pt + n); int Max = -inf; for (int i = 0; i < n; ++i) { for (int k = 0; k <= m; ++k) dp[i][k] = -inf; dp[i][0] = 0; Max = max(Max, pt[i].a); dp[i][1] = Max; } for (int k = 2; k <= m; ++k) { for (int i = k-1; i < n; ++i) { dp[i][k] = max(dp[i-1][k], dp[i-1][k-1] + pt[i].a - (k-1) * pt[i].b); } } return dp[n-1][m]; } int main() { cin >> n >> m; for (int i = 0; i < n; ++i) cin >> A[i]; for (int i = 0; i < n; ++i) cin >> B[i]; cout << solve() << endl; // cout << greedy() << endl; return 0; }
- 长度为
的合法括号序列,给每个括号染色,规则是:
- 每个括号和其对应的括号,其中一个必须是红色,另一个是绿色或者蓝色
- 相邻的两个括号颜色不能相同
求所有染色方案数。对 998244353 取模。
想法:只通过 36%
区间 DP。令表示处理完区间
且 l 位置染色为 i,r 位置染色为 j 的方案数,其中
, 0, 1 和 2 分别表示红色,绿色和蓝色。对于每个位置
的括号,记录其对应括号的位置为
。
考虑更新,分两种
- 如果
, 则由
更新
- 如果
,则由
和
更新得到。
更新时枚举每个区间端点的颜色。
时间复杂度:。
#include <bits/stdc++.h> #define IOS ios_base::sync_with_stdio(0); cin.tie(0); using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; const ll mod = 998244353; const int N = 510; int n; string s; int match[N]; ll dp[N][N][3][3]; inline void add(ll& x, ll y) { x = (x + y % mod) % mod; } void solve(int l, int r) { if (l + 1 == r) { dp[l][r][0][1] = dp[l][r][0][2] = 1; dp[l][r][1][0] = dp[l][r][2][0] = 1; return; } else if (l > r) return; solve(l+1, match[l+1]); if (match[l+1] + 1 == r) { for (int i1 = 0; i1 < 3; ++i1) { for (int j1 = 0; j1 < 3; ++j1) if (i1 == 0 || j1 == 0) { if (i1 == 0 && j1 == 0) continue; for (int i2 = 0; i2 < 3; ++i2) { for (int j2 = 0; j2 < 3; ++j2) if (i2 == 0 || j2 == 0) { if (i2 == 0 && j2 == 0) continue; if (i1 != 0 && i1 == i2) continue; if (j1 != 0 && j1 == j2) continue; add(dp[l][r][i1][j1], dp[l+1][r-1][i2][j2]); } } } } } else { int p = match[l+1] + 1; solve(p, r-1); for (int i1 = 0; i1 < 3; ++i1) { for (int j1 = 0; j1 < 3; ++j1) if (i1 == 0 || j1 == 0) { if (i1 == 0 && j1 == 0) continue; for (int i2 = 0; i2 < 3; ++i2) { for (int j2 = 0; j2 < 3; ++j2) if (i2 == 0 || j2 == 0) { if (i2 == 0 && j2 == 0) continue; for (int i3 = 0; i3 < 3; ++i3) { for (int j3 = 0; j3 < 3; ++j3) if (i3 == 0 || j3 == 0) { if (i3 == 0 && j3 == 0) continue; if (i1 != 0 && i1 == i2) continue; if (j2 != 0 && j2 == i3) continue; if (j3 != 0 && j3 == j1) continue; add(dp[l][r][i1][j1], 1LL * dp[l+1][p-1][i2][j2] * dp[p][r-1][i3][j3] % mod); } } } } } } } } int main() { IOS; cin >> n >> s; stack<int> sta; for (int i = 0; i < n; ++i) { if (s[i] == '(') sta.push(i); else { int t = sta.top(); sta.pop(); match[i] = t; match[t] = i; } } solve(0, n-1); ll ans = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) add(ans, dp[0][n-1][i][j]); } cout << ans << endl; return 0; }#百度春招##笔试题目##百度##算法工程师#