[赛记] 冲刺CSP联训模拟1[衡中]
几何 100pts
赛时打的 $ DP $ 没有用 bitset
优化过了,也是放过了暴力;
考虑设状态 $ f_{i, j, k} $ 表示考虑到第 $ i $ 位,到第 $ j $ 位 $ x $ 和第 $ k $ 位 $ y $ 可不可取,直接转移即可;
时间复杂度:$ \Theta(|s||x||y|) $,应该是过不了的;
点击查看暴力
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int t;
char s[500005], x[55], y[55];
int sl, xl, yl;
bool f[2][52][52];
int main() {
freopen("geometry.in", "r", stdin);
freopen("geometry.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--) {
cin >> (s + 1);
cin >> (x + 1);
cin >> (y + 1);
memset(f, false, sizeof(f));
sl = strlen(s + 1);
xl = strlen(x + 1);
yl = strlen(y + 1);
f[0][xl][0] = true;
f[0][0][yl] = true;
for (int i = 1; i <= sl; i++) {
memset(f[i & 1], false, sizeof(f[i & 1]));
for (int j = 0; j <= xl; j++) {
for (int k = 0; k <= yl; k++) {
if (s[i] == x[j]) {
if (j - 1 == 0) {
f[i & 1][j][k] |= f[(i - 1) & 1][xl][k];
f[i & 1][j][k] |= f[(i - 1) & 1][0][k];
} else {
f[i & 1][j][k] |= f[(i - 1) & 1][j - 1][k];
}
}
if (s[i] == y[k]) {
if (k - 1 == 0) {
f[i & 1][j][k] |= f[(i - 1) & 1][j][0];
f[i & 1][j][k] |= f[(i - 1) & 1][j][yl];
} else {
f[i & 1][j][k] |= f[(i - 1) & 1][j][k - 1];
}
}
}
}
}
if (f[sl & 1][xl][yl] || f[sl & 1][xl][0] || f[sl & 1][0][yl]) {
cout << "Yes" << '\n';
} else {
cout << "No" << '\n';
}
}
return 0;
}
根据我们以前的经验,我们可以将答案与状态后两维中的一位互换,所以设 $ f_{i, j} = k $ 表示考虑前 $ i $ 位,到第 $ j $ 位 $ x $ 时所有合法的 $ y $ 的状态,这时我们就可以用 bitset
来存储 $ f $ 数组,进而转移;
转移其实就是循环移位和按位与和按位或的操作;
时间复杂度:$ \Theta(\frac{|s||x||y|}{w}) $;
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <bitset>
using namespace std;
int t;
char s[500005], x[55], y[55];
int sl, xl, yl;
bitset<55> f[2][52];
bitset<55> g[500005];
bitset<55> Y(bitset<55> x) {
int y = x[yl];
bitset<55> bit = (x << 1);
if (y) bit[1] = 1;
return bit;
}
int main() {
freopen("geometry.in", "r", stdin);
freopen("geometry.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--) {
cin >> (s + 1);
cin >> (x + 1);
cin >> (y + 1);
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
sl = strlen(s + 1);
xl = strlen(x + 1);
yl = strlen(y + 1);
for (int i = 1; i <= sl; i++) {
for (int j = 1; j <= yl; j++) {
if (s[i] == y[j]) g[i][j] = 1;
}
}
f[0][0][0] = 1;
for (int i = 1; i <= sl; i++) {
memset(f[i & 1], 0, sizeof(f[i & 1]));
for (int j = 0; j <= xl; j++) {
if (s[i] == x[j]) {
f[i & 1][j] |= f[(i - 1) & 1][j - 1];
if (j - 1 == 0) f[i & 1][j] |= f[(i - 1) & 1][xl];
}
bitset<55> b = Y(f[(i - 1) & 1][j]);
b &= g[i];
f[i & 1][j] |= b;
}
}
if (f[sl & 1][xl][yl] || f[sl & 1][xl][0] || f[sl & 1][0][yl]) {
cout << "Yes" << '\n';
} else {
cout << "No" << '\n';
}
}
return 0;
}
分析 0pts
$ DP $,。。。
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
long long a, b;
long long f[500005][2][2], w[2][2];
struct sss{
int t, ne;
}e[2000005];
int h[2000005], cnt;
void add(int u, int v) {
e[++cnt].t = v;
e[cnt].ne = h[u];
h[u] = cnt;
}
void dfs(int x, int fa) {
f[x][0][0] = 0;
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa) continue;
dfs(u, x);
for (int j = 0; j <= 1; j++) {
for (int k = 0; k <= 1; k++) {
w[j][k] = f[x][j][k];
f[x][j][k] = 0x3f3f3f3f3f3f3f3f;
}
}
for (int j = 0; j <= 1; j++) {
for (int k = 0; k <= 1; k++) {
for (int uj = 0; uj <= 1; uj++) {
for (int uk = 0; uk <= 1; uk++) {
f[x][j][k | uj | uk] = min(f[x][j][k | uj | uk], w[j][k] + f[u][uj][uk] + a);
long long now = 0;
if (j && uj) {
now = -b;
} else if (!j && !uj) {
now = b;
}
f[x][j ^ 1][k | (uj ^ 1) | uk] = min(f[x][j ^ 1][k | (uj ^ 1) | uk], w[j][k] + f[u][uj][uk] + now);
}
}
}
}
}
}
int main() {
freopen("analyse.in", "r", stdin);
freopen("analyse.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
cin >> a >> b;
a = min(a, b);
int x, y;
for (int i = 1; i <= n - 1; i++) {
cin >> x >> y;
add(x, y);
add(y, x);
}
memset(f, 0x3f, sizeof(f));
dfs(1, 0);
cout << min({f[1][0][0], f[1][0][1] - b, f[1][1][0] - b, f[1][1][1] - b});
return 0;
}