[赛记] csp-s模拟6
一般图最小匹配 35pts
纯纯的错解35pts;
考虑将原数列排序,那么我们选的边就只能是相邻两个点的;
发现这玩意能够递推(赛时没发现),所以直接 $ DP $,设 $ f_{i, j} $ 表示当前考虑到第 $ i $ 位,有 $ j $ 条边被选的最小权值,转移时考虑第 $ i $ 个点连不连第 $ i - 1 $ 个点即可;
时间复杂度:$ \Theta(nm) $;
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m;
long long a[5005];
long long f[5005][5005];
int main() {
freopen("match.in", "r", stdin);
freopen("match.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
memset(f, 0x3f, sizeof(f));
f[0][0] = 0;
f[2][1] = a[2] - a[1];
f[2][0] = 0;
f[1][0] = 0;
for (int i = 3; i <= n; i++) {
for (int j = 0; j <= min(i / 2, m); j++) {
if (j == 0) {
f[i][j] = f[i - 1][j];
continue;
}
f[i][j] = min(f[i - 1][j], f[i - 2][j - 1] + a[i] - a[i - 1]);
}
}
cout << f[n][m];
return 0;
}
重定向 95pts
少判断了一种情况,95pts;
大力分讨,对于两个数 $ a_i, a_{i + 1} $,考虑它们的四种 $ 0, 1 $ 情况,然后分别搞一搞就行;
注意多测,数组要清空;
还要注意 $ 0 $ 的时候可以把后面较小的数删掉放到这里来;
时间复杂度:$ \Theta(n \log n) $,瓶颈在二分查找 + 遍历和排序上;
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int t;
int n;
int a[2000005], b[2000005], c[2000005], mi[2000005], ans[2000005];
int main() {
freopen("repeat.in", "r", stdin);
freopen("repeat.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i] = a[i];
}
sort(b + 1, b + 1 + n);
int csum = 0;
for (int i = 1; i <= n; i++) {
int o = lower_bound(b + 1, b + 1 + n, i) - b;
if (b[o] != i) {
c[++csum] = i;
}
}
int mipos = n + 1;
a[n + 1] = 0x3f3f3f3f;
for (int i = n; i >= 1; i--) {
if (a[i] == 0) mi[i] = mipos;
else if (a[i] < a[mipos]) {
mipos = i;
}
}
int now = 1;
int pos = 0;
for (int i = 1; i <= n - 1; i++) {
if (a[i] != 0 && a[i + 1] != 0) {
if (a[i] > a[i + 1]) {
pos = i;
c[++csum] = a[i];
break;
}
}
if (a[i] == 0 && a[i + 1] != 0) {
if (c[now] > a[mi[i]]) {
if (a[mi[i]] < a[i + 1]) {
pos = mi[i];
c[++csum] = a[mi[i]];
break;
} else {
pos = i;
break;
}
} else {
if (c[now] > a[i + 1]) {
pos = i;
break;
} else {
now++;
}
}
}
if (a[i] != 0 && a[i + 1] == 0) {
if (a[i] > c[now]) {
pos = i;
c[++csum] = a[i];
break;
}
}
if (a[i] == 0 && a[i + 1] == 0) {
if (a[mi[i]] < c[now]) {
pos = mi[i];
c[++csum] = a[mi[i]];
break;
}
now++;
}
}
sort(c + 1, c + 1 + csum);
if (pos == 0) pos = n;
now = 1;
int asum = 0;
for (int i = 1; i <= n; i++) {
if (pos == i) continue;
if (a[i] != 0) ans[++asum] = a[i];
else {
ans[++asum] = c[now];
now++;
}
}
for (int i = 1; i <= asum; i++) {
cout << ans[i] << ' ';
}
cout << '\n';
for (int i = 1; i <= n; i++) {
a[i] = 0;
b[i] = 0;
c[i] = 0;
mi[i] = 0;
ans[i] = 0;
}
}
return 0;
}
斯坦纳树 35pts
200行暴力35pts;
点击查看暴力
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
struct sss{
int t, ne;
long long w;
}e[1000005];
int h[1000005], cnt;
void add(int u, int v, long long ww) {
e[++cnt].t = v;
e[cnt].ne = h[u];
h[u] = cnt;
e[cnt].w = ww;
}
struct sas{
int f, t;
long long w;
bool operator <(const sas &A) const {
return w < A.w;
}
}ed[1000005];
int f[500005];
int find(int x) {
if (x != f[x]) f[x] = find(f[x]);
return f[x];
}
int ecnt;
int fa[500005], dep[500005], siz[500005], dfn[500005], nfd[500005], hson[500005], htop[500005], dcnt;
long long a[500005];
int b[500005], bcnt;
bool vis[500005];
bool cmp(int x, int y) {
return dfn[x] < dfn[y];
}
namespace SEG{
inline int ls(int x) {
return x << 1;
}
inline int rs(int x) {
return x << 1 | 1;
}
struct sss{
int l, r;
long long sum;
}tr[3000005];
inline void push_up(int id) {
tr[id].sum = tr[ls(id)].sum + tr[rs(id)].sum;
}
void bt(int id, int l, int r) {
tr[id].l = l;
tr[id].r = r;
if (l == r) {
tr[id].sum = a[nfd[l]];
return;
}
int mid = (l + r) >> 1;
bt(ls(id), l, mid);
bt(rs(id), mid + 1, r);
push_up(id);
}
long long ask(int id, int l, int r) {
if (tr[id].l >= l && tr[id].r <= r) {
return tr[id].sum;
}
int mid = (tr[id].l + tr[id].r) >> 1;
if (r <= mid) return ask(ls(id), l, r);
else if (l > mid) return ask(rs(id), l, r);
else return ask(ls(id), l, mid) + ask(rs(id), mid + 1, r);
}
}
namespace TCS{
void dfs1(int x, int f) {
fa[x] = f;
dep[x] = dep[f] + 1;
hson[x] = -1;
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == f) continue;
dfs1(u, x);
siz[x] += siz[u];
if (hson[x] == -1 || siz[hson[x]] < siz[u]) hson[x] = u;
}
}
void dfs(int x) {
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa[x]) continue;
a[u] = e[i].w;
dfs(u);
}
}
void dfs2(int x, int t) {
htop[x] = t;
dfn[x] = ++dcnt;
nfd[dcnt] = x;
if (hson[x] == -1) return;
dfs2(hson[x], t);
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa[x] || u == hson[x]) continue;
dfs2(u, u);
}
}
int lca(int x, int y) {
while(htop[x] != htop[y]) {
if (dep[htop[x]] < dep[htop[y]]) swap(x, y);
x = fa[htop[x]];
}
if (dfn[x] > dfn[y]) swap(x, y);
return x;
}
long long ask(int x, int y) {
long long ans = 0;
while(htop[x] != htop[y]) {
if (dep[htop[x]] < dep[htop[y]]) swap(x, y);
ans += SEG::ask(1, dfn[htop[x]], dfn[x]);
x = fa[htop[x]];
}
if (x == y) return ans;
if (dfn[x] > dfn[y]) swap(x, y);
ans += SEG::ask(1, dfn[x] + 1, dfn[y]);
return ans;
}
}
long long Kru() {
long long ans = 0;
for (int i = 1; i <= bcnt; i++) {
for (int j = i + 1; j <= bcnt; j++) {
ed[++ecnt] = {b[i], b[j], TCS::ask(b[i], b[j])};
}
}
sort(ed + 1, ed + 1 + ecnt);
for (int i = 1; i <= n; i++) {
f[i] = i;
}
int tot = 0;
for (int i = 1; i <= ecnt; i++) {
if (tot == bcnt - 1) break;
int x = find(ed[i].f);
int y = find(ed[i].t);
if (x != y) {
f[x] = y;
ans += ed[i].w;
}
}
return ans;
}
int main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
int x, y;
long long w;
for (int i = 1; i <= n - 1; i++) {
cin >> x >> y;
cin >> w;
add(x, y, w);
add(y, x, w);
}
TCS::dfs1(1, 0);
TCS::dfs(1);
TCS::dfs2(1, 1);
SEG::bt(1, 1, dcnt);
if (n <= 500) {
for (int i = 1; i <= n; i++) {
cin >> x;
b[++bcnt] = x;
if (i == 1) {
cout << 1;
continue;
}
sort(b + 1, b + 1 + bcnt, cmp);
for (int j = 1; j <= n; j++) vis[j] = false;
long long ans = 0;
int lc = b[1];
for (int j = 2; j <= bcnt; j++) {
lc = TCS::lca(lc, b[j]);
}
for (int j = 1; j <= bcnt; j++) {
int x = b[j];
while(x != lc) {
if (!vis[x]) {
vis[x] = true;
ans += a[x];
}
x = fa[x];
}
}
ecnt = 0;
long long sum = Kru();
if (sum == ans) cout << 1;
else cout << 0;
}
return 0;
}
for (int i = 1; i <= n; i++) cout << 1;
return 0;
}
其实正解也很暴力,考虑其正确当且仅当所有出现过的点的 $ lca $ 也出现过(即没有一个在出现过的点构成的虚树中没有出现过的点的度数 $ \geq 3 $);
但是有边权为 $ 0 $ 的情况,我们将其缩成一个点即可;
那么我们可以钦定 $ b_1 $ 为根(有些人类智慧),然后每次遍历到一个新的 $ b_i $ 时就往上跳并把路径上经过的点标记一下,看第一个到达的被标记过的点在不在已经有的点中,若全都在则满足要求;
发现每个点最多只会被遍历一次,保证了时间复杂度;
对于不在的点的维护,我用的 set
(主要是因为 erase
empty
insert
好用),所以时间复杂度为 $ \Theta(n \log n) $;
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
int n;
struct sss{
int t, ne;
long long w;
}e[1000005];
int h[1000005], cnt;
void add(int u, int v, int ww) {
e[++cnt].t = v;
e[cnt].ne = h[u];
h[u] = cnt;
e[cnt].w = ww;
}
int b[500005];
int belog[500005], sum;
void dfs(int x, int fa) {
belog[x] = sum;
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa || belog[u]) continue;
if (e[i].w == 0) dfs(u, x);
}
}
int x[500005], y[500005];
long long w[500005];
vector<int> v[500005];
int fa[500005];
bool vis[500005], vi[500005];
void afs(int x, int f) {
fa[x] = f;
for (int i = 0; i < v[x].size(); i++) {
int u = v[x][i];
if (u == f) continue;
afs(u, x);
}
}
set<int> s;
int main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n - 1; i++) {
cin >> x[i] >> y[i];
cin >> w[i];
add(x[i], y[i], w[i]);
add(y[i], x[i], w[i]);
}
sum = 0;
for (int i = 1; i <= n; i++) {
if (!belog[i]) {
sum++;
dfs(i, 0);
}
}
for (int i = 1; i <= n - 1; i++) {
if (belog[x[i]] != belog[y[i]]) {
v[belog[x[i]]].push_back(belog[y[i]]);
v[belog[y[i]]].push_back(belog[x[i]]);
}
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
afs(belog[b[1]], 0);
cout << 1;
vis[belog[b[1]]] = true;
vi[belog[b[1]]] = true;
for (int i = 2; i <= n; i++) {
int x = belog[b[i]];
while(!vis[x]) {
vis[x] = true;
x = fa[x];
}
vi[belog[b[i]]] = true;
if (!vi[x]) {
s.insert(x);
}
s.erase(belog[b[i]]);
if (s.empty()) {
cout << 1;
} else {
cout << 0;
}
}
return 0;
}