[赛记] 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;
}
posted @ 2024-10-05 11:01  Peppa_Even_Pig  阅读(16)  评论(0编辑  收藏  举报