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,血坑
#小马智行##笔经##笔试题目#
顺丰集团工作强度 345人发布