9.26 pony.ai小马智行ak代码
1. 排序贪心
易得,相邻元素尽可能相邻结果最优。O(nlong)
#include <iostream> #include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; typedef long long ll; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); ll res = 0; for (int i = 0; i < n - 1; i++) { res += (a[i] - a[i + 1]) * (a[i] - a[i + 1]); } cout << res << endl; return 0; }
2. 二分+滑窗
二分解,如果当前可以,那么尝试更小的O(NlogN)
#include <iostream> #include <bits/stdc++.h> using namespace std; bool isvalid(string &s, int m) { vector<int> a(26, 0); vector<bool> ok(26, false); bool flag = false; for (int i = 0; i < m; i++) { a[s[i] - 'a']++; } for (int i = 0; i < 26; i++) { if (a[i] > 0) { ok[i] = true; } } for (size_t i = m; i < s.size(); i++) { int idx = s[i - m] - 'a'; a[idx]--; a[s[i] - 'a']++; if (a[idx] == 0) { ok[idx] = false; } } for (int i = 0; i < 26; i++) { if (ok[i]) { flag = true; } } return flag; } int main() { string s; cin >> s; int n = s.size(); int l = 0; int r = n; while (l < r) { int m = l + (r - l) / 2; bool flag = isvalid(s, m); if (flag) { r = m; } else { l = m + 1; } } if (isvalid(s, l)) cout << l << endl; else cout << l + 1<< endl; return 0; }
3. 并查集
相邻的合并,最后找同一root下的最小代价的就可以,近似O(N)
#include <iostream> #include <bits/stdc++.h> using namespace std; struct UF{ UF(int n) { fa = vector<int>(n); for (int i = 0; i < n; i++) fa[i] = i; } int find(int x) { if (fa[x] == x) return fa[x]; fa[x] = find(fa[x]); return fa[x]; } void join(int x, int y) { int rootx = find(x); int rooty = find(y); if (rootx == rooty) return; fa[rootx] = rooty; } vector<int> fa; }; int main() { int n, m; cin >> n >> m; UF uf(n + 1); vector<int> a(n + 1); for (int i = 1; i <= n; i++) { cin >> a[i]; } for (int i = 0; i < m; i++) { int x, y; cin >> x >> y; uf.join(x, y); } int res = 0; unordered_map<int, int> mp; for (int i = 1; i <= n; i++) { int root = uf.find(i); if (mp.find(root) == mp.end()) { mp[root] = a[i]; } else { mp[root] = min(mp[root], a[i]); } } for (auto &it : mp) { res += it.second; } cout << res << endl; return 0; }
4 组合数+dp
dp[i] 表示 从第0个到第i个数一共多少可能,
不取第i个数,那么就是dp[i - 1]
取第i个数,那么我们分别枚举起点第j 个起点 j 取 [0, i)
如果[j ... i]的某个序列是ok的,那么这个序列的长度一定是 a[j] + 1,
又j和i是必须取的,所以只需在[j, i] 中取 a[j] - 1 个数, 这就是组合数
然后再乘上dp[j - 1] 因为前面有这么多种可能。
这种做法是不会重复的,可以证明,但懒得敲了qaq..
#include <iostream> #include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } vector<vector<int>> c(1005, vector<int>(1005, 0)); c[0][0] = 1; const long long MOD = 998244353; for (int i = 1; i <= 1002; i++) { for (int j = 0; j <= i; j++) { c[i][j] = c[i - 1][j] + (j >= 1 ? c[i - 1][j - 1] : 0); c[i][j] = c[i][j] % MOD; } } vector<int> dp(n); for (int i = 1; i < n; i++) { dp[i] = dp[i - 1]; for (int j = 0; j < i; j++) { if (a[j] >= 1) { dp[i] = (dp[i] + (1ll * c[i - j - 1][a[j] - 1] * (j == 0 ? 1 : dp[j - 1] + 1) % MOD)) % MOD; } } } cout << dp[n - 1] << endl; return 0; }
注意long long,血坑
#小马智行##笔经##笔试题目#