2025CSP-S模拟赛38 比赛总结

2025CSP-S模拟赛38

T1 T2 T3 T4
30 TLE 0 WA 0 WA 27 TLE

总分:57;排名:16/22

T1 玩了很久无果,拼了个暴力。二三不会,T4 是暴力。

T1 黑暗料理

赛时觉得此题很 2-SAT。但是由于对于 2-SAT 板子的理解不足以及并没有意识到:2-SAT 只能求出一种合法的解,并无法求出最优解。然后我们就失败了。

正解来了。考虑到只有 1+1 和奇数+偶数会产生质数。然后呢,你发现这个多于一个的 1 都是无用的。你现在只保留一个 1,其他的 1 扔掉,然后把加和为质数的点连边,你就发现这构成了一张二分图(奇数点作为左部,偶数点作为右部),答案就是此图的最大独立集。

题解给的是拿网络流求这个最大独立集(家人们,S 组 T1 考网络流),但是其实匈牙利是可做的。你发现这个图有 \(n\) 个点,就很无脑的去想,最多有 \((\frac{n}{2})^2\) 条边,然后你的复杂度就是一个 \(\frac{n^3}{4}\),然后很妙啊,你的 \(T \le 4\)。然后 750 完全跑得过 \(n^3\)

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
const int N = 1500 + 10;
int n, a[N];
il int fpow(int a, int x, int MOD) {
	int ans = 1;
	while (x) {
		if (x & 1) ans = 1ll * ans * a % MOD;
		a = 1ll * a * a % MOD;
		x >>= 1;
	}
	return ans;
}
int Test[20] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
int test_time = 12;
bool isPrime(int p) {
	if (p < 2) return 0;
	int t = p - 1, k = 0;
	while (!(t & 1)) {
		t >>= 1;
		k++; 
	}
	for (int i = 0; i < test_time; i++) {
		if (p == Test[i]) return 1;
		int a = fpow(Test[i], t, p);
		for (int j = 1; j <= k; j++) {
			if (1ll * a * a % p == 1 && a != 1 && a != p - 1) { 
				return 0;
			}
			a = 1ll * a * a % p;
		}
		if (a != 1) return 0;
	}
	return 1;
}
vector<int> G[N];
int vis[N], pei[N];
il bool dfs(int x) {
	for (int y : G[x]) {
		if (vis[y]) continue;
		vis[y] = 1;
		if (!pei[y] || dfs(pei[y])) {
			pei[y] = x;
			return true;
		}
	}
	return false;
}
int t[N];
int solve() {
	n = read();
	for (int i = 1; i <= n; i++) G[i].clear();
	for (int i = 1; i <= n; i++) {
		a[i] = read();
	}
	int cnt = 0;
	for (int i = 1; i <= n; i++) t[i] = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i] % 2 == 0) continue;
		if (a[i] == 1) {
			cnt++;
			if (cnt > 1) {
				t[i] = 1;
				continue;
			} 
		}
		for (int j = 1; j <= n; j++) {
			if (a[j] % 2 == 1) continue;
			if (isPrime(a[i] + a[j])) {
				G[i].push_back(j);
			}
		}
	}
	for (int i = 1; i <= n; i++) pei[i] = 0;
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		if (t[i] || a[i] % 2 == 0) continue;
		for (int j = 1; j <= n; j++) vis[j] = 0;
		if (dfs(i)) ans++;
	}
	printf("%d\n", n - max(0, cnt - 1) - ans);
	
	return 0;
}
signed main() {
	int qq = read();
	while (qq--) {
		solve();
	}
	
	return 0;
}

T2 爆炸

你一个炸弹如果是横向的被炸到那么他自己肯定是考虑纵向去炸,反之亦然。

去考虑对于每个炸弹和它上下左右的第一个炸弹连边。然后就会形成若干个连通块。考虑对每个连通块统计答案然后取其最大值即为答案。

不难发现,一个连通块要么是个环,要么是棵树。考虑如果是环怎么做。不是都说到这儿了你还不会?滚吧。你就 dfs 把他炸弹会炸到哪些行哪些列搞出来,然后一加,因为他会有相交的点会重复计算,暴力统计一下即可,复杂度均摊。那么对于树,无非是环删掉一条边,你就考虑在刚才那个玩意儿的基础上去删掉一行或一列即可。

这傻逼题考试时没写出来就是活该。我就是废物,这傻逼题有啥技术含量写不出来。

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 3000 + 10;
int n, m, kk, bb;
char S[N][N];
int a[N][N];
vector<int> G[N * N];
int tot, id[N][N], ii[N * N], jj[N * N];
il void link(int x, int y) {
	G[x].push_back(y);
	G[y].push_back(x);
}
int vis[N * N], fl;
vector<int> tmp;
il void dfs(int x, int fr) {
	if (vis[x]) {
		fl = 1;
		return;
	}
	vis[x] = 1;
	tmp.push_back(x);
	for (int y : G[x]) {
		if (y == fr) continue;
		dfs(y, x);
	}
}
int ti[N], tj[N], si[N], sj[N];
vector<int> idx, idy;
int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> m >> kk >> bb;
	for (int i = 1; i <= n; i++) {
		cin >> (S[i] + 1);
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (S[i][j] == '.') a[i][j] = 0;
			if (S[i][j] == 'k') a[i][j] = 1;
			if (S[i][j] == 'b') a[i][j] = 2;
			if (a[i][j] == 1) {
				si[i] += 1, sj[j] += 1;
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (a[i][j] != 2) continue;
			id[i][j] = ++tot;
			for (int k = i - 1; k >= 1; k--) {
				if (a[k][j] == 2) {link(id[k][j], id[i][j]); break;}
			}
			for (int k = j - 1; k >= 1; k--) {
				if (a[i][k] == 2) {link(id[i][k], id[i][j]); break;}
			}
			ii[id[i][j]] = i, jj[id[i][j]] = j;
		}
	}
	int ans = 0;
	for (int x = 1; x <= tot; x++) {
		if (vis[x]) continue;
		fl = 0;
		tmp.clear(), idx.clear(), idy.clear();
		dfs(x, 0);
		for (int i = 1; i <= n; i++) ti[i] = 0;
		for (int j = 1; j <= m; j++) tj[j] = 0;
		for (int i : tmp) {
			ti[ii[i]]++;
			tj[jj[i]]++;
		}
		int sum = 0;
		for (int i = 1; i <= n; i++) {
			if (ti[i]) sum += si[i], idx.push_back(i);
		}
		for (int j = 1; j <= m; j++) {
			if (tj[j]) sum += sj[j], idy.push_back(j);
		}
		for (int i : idx) {
			for (int j : idy) {
				if (a[i][j] == 1) {
					si[i]--, sj[j]--; 
					sum--;
				}
			}
		}
		if (!fl) {
			int mx = -INF;
			for (int i = 1; i <= n; i++) {
				if (ti[i] == 1) mx = max(mx, -si[i]);
			}
			for (int j = 1; j <= m; j++) {
				if (tj[j] == 1) mx = max(mx, -sj[j]);
			}
			sum += mx;
		}
		ans = max(ans, sum);
	}
	cout << ans << "\n";
	
	return 0;
}

T3 游戏

T4 公司

posted @ 2025-08-20 15:06  Zctf1088  阅读(44)  评论(0)    收藏  举报