Codeforces Round #683 (Div. 2, by Meet IT)
题意:
给你一个字符串 s s s,和 t t t 问 s , t s, t s,t的所有子串中 最长公共子序列 * 4 减去 两个子串的长度的最大值是多少。
题解:
考虑暴力:
用 dfs进行模拟, 如果当前 s [ i ] = = t [ j ] s[i] == t[j] s[i]==t[j] 那么这个字符产生贡献有两种
第一种是 取 i与j的字符, 那么此时的答案是 + 4 -1 -1, 然后 i + 1, j + 1
第二种是不取, 直接走, i + 1,或 j + 1
如果 f == 1说明前面已经有匹配, 此时如果选择直接走那么 答案会 -1
如果 f == 0说明前面没用匹配, 此时如果选择直接走不会答案产生贡献。
最后再加个记忆化(相同参数只走一次)时间复杂度为 o(n * m)。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5007;
char s[N], t[N];
int n, m;
int dp[N][N][2];
int dfs(int i, int j, int f) {
if (i > n || j > m) return 0;
if (dp[i][j][f] != -1) return dp[i][j][f];
int ans = 0;
if (s[i] == t[j]) {
ans = max(ans, dfs(i + 1, j + 1, 1) + 2);
if (f) {
ans = max(ans, dfs(i + 1, j, f) - 1);
ans = max(ans, dfs(i, j + 1, f) - 1);
} else {
ans = max(ans, dfs(i + 1, j, f));
ans = max(ans, dfs(i, j + 1, f));
}
} else {
if (f) {
ans = max(ans, dfs(i + 1, j, f) - 1);
ans = max(ans, dfs(i, j + 1, f) - 1);
} else {
ans = max(ans, dfs(i + 1, j, f));
ans = max(ans, dfs(i, j + 1, f));
}
}
return dp[i][j][f] = ans;
}
int main() {
ios::sync_with_stdio(0);
cin >> n >> m;
cin >> (s + 1) >> (t + 1);
memset(dp, -1, sizeof(dp));
cout << dfs(1, 1, 0) << endl;
}
给你 n n n 个不同的数, 将 每个 a [ i ] a[i] a[i] ( i ∈ n ) (i \in n) (i∈n) 与剩余的数进行异或选择一个异或值最小的数, 然后将这两个数连接一条边, 你可再这n个数进行删除, 问最少删除多少个数可以将 剩下的数字连成一颗树
题解:
看到异或第一反应就是想到字典树, 我们可以把每个数插入到字典树中,
对于一个字典树, 如果存在两个有相同父亲的叶子节点, 那么这两个简单异或和肯定最小(因为上面的信息都一样异或后就是 0)那么这两个节点肯定可以相互连边, 所有说这两个节点肯定是一个联通快了。
那么, 如何让这个联通快与其它节点相连呢?
也就是对于字典树中的每个节点, 左儿子或者右儿子只能再某个儿子中取一个数,(如果都取大于等于两个数那么这两个儿子所构成的联通快将无法连接)然后对于不取一个数的儿子也是一样。 暴力枚举字典树求一个保留节点数最多的方案。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
int a[N], n, tree[30*N][2];
int top = 2;
void insert(int x) {
int now = 1;
for (int i = 30; i >= 0; i--) {
int id = ((x >> i) & 1);
if (!tree[now][id]) {
tree[now][id] = top++;
}
now = tree[now][id];
}
}
int sz[N], ans = 0;
int work(int u, int dep) {
if (dep == 0) {
return 1;
}
int ans = 0;
if (tree[u][0] && tree[u][1]) {
ans = max(ans, work(tree[u][0], dep - 1) + 1);
ans = max(ans, work(tree[u][1], dep - 1) + 1);
} else if (tree[u][0]) {
ans = max(ans, work(tree[u][0], dep - 1));
} else if (tree[u][1]) {
ans = max(ans, work(tree[u][1], dep - 1));
}
return ans;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
insert(a[i]);
}
int ans = work(1, 31);
cout << n - ans << endl;
}