第一次模拟赛总结

第一次摸底考试 总结

考试结果

成绩:\(100+100+80+0+70+0=350\)

排名:#\(18\)

逐题分析

C 钱到题

出现の问题

  1. 约瑟夫环使用了数组进行维护,取模麻烦,使用 std::queue 更为方便

坑点

  1. 队列 q 需要进行初始化

正确代码

#include <bits/stdc++.h>
using namespace std;

int main() {
	int n, k;
	cin >> n >> k;
	queue<int> q; // 维护环 
	for (int i = 1; i <= n; i ++) q.push(i);
	vector<int> w(n + 1, 1); // 记录每人积分
	for (int i = 1; i <= k; i ++) {
		int x, y;
		cin >> x >> y;
		while (x--) {
			int u = q.front();
			q.pop();
			if (x == 0) {
				w[u] += y;
			}
			if (w[u]) q.push(u);
			else cout << u << " ";
		}
	}
	cout << endl;
	return 0;
} 

D 浅岛题

出现の问题

  1. 第二级骗分(uv 的祖先时,未使用 while 循环进行修改操作)
  2. 第四级骗分 其实就是正解(思维题:并非 LCA,而可以使用数组直接实现 op == 1 的情况)

根据提示,异或两次等于没有异或,所以 𝑢𝑣 路径上的点的异或和其实没有改变。每次只需要 \(𝑂(1)\) 地修改 𝑎[𝑢]𝑎[𝑣] 即可。

坑点

  1. 无需使用邻接表存图,一个数组即可
  2. vector 初始化不使用赋值,使用按位异或

正确代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int main() {
	ll n = 0, q = 0;
	cin >> n >> q;
	vector<ll> a(n + 1);
	for (int i = 1; i < n; i ++) {
		ll u, v, x;
		cin >> u >> v >> x;
		a[u] ^= x;
		a[v] ^= x;
	}
	
	for (int i = 1; i <= q; i ++) {
		ll op, u, v, x;
		cin >> op;
		if (op == 1) {
			cin >> u >> v >> x;
			a[u] ^= x;
			a[v] ^= x;
		} else {
			cin >> u;
			cout << a[u] << endl;
		}
	}
	return 0;
}

E 迁到题

出现の问题

  1. 骗分(\(70pts\))√
  2. 正解:对于这种最优解题目,没有想到使用动态规划 dp 解决。

坑点

dp 状态

使用三维数组,设 \(f(x, y, z)\) 为从起点走到格子 \((x, y)\),使用 \(z\) 个道具所能获得的最大得分。

dp 转移

因为题目要求,每一个格子只可以从上面或者左边转移,所以推出转移方程:

\[f(x, y, z) = \begin{cases} max(f(x - 1, y, z, f(x, y - 1, z))) & s_{x, y} = 0 \\ max(f(x - 1, y, z, f(x, y - 1, z))) + 1 & s_{x, y} = 1 \\ max(f(x - 1, y, z), f(x, y - 1, z), f(x, y, z - 1) + 1) & s_{x, y} = ? \\ \end{cases} \]

  • 注意:第三行的 \(f(x, y, z - 1) + 1\) 尤为关键。(消耗一次魔法使用问号的机会)
  • 注意:z 一定要从大到小遍历!
  • 注意:z 的枚举范围:for (int z = k; z >= 0; z --)

正确代码

#include <bits/stdc++.h>
using namespace std;

int n, m, k;
char arr[105][105];
long long f[105][105][105]; // 设 dp(x, y, z) 为从起点走到格子 (x, y),使用 z 个道具所能获得的最大得分。

int main() {
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j <= m; j ++) {
			cin >> arr[i][j];
		}
	}
	
	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j <= m; j ++) {
			for (int l = k; l >= 0; l --) {
				f[i][j][l] = max(f[i - 1][j][l], f[i][j - 1][l]);
				if (arr[i][j] == '1') {
					f[i][j][l] ++;
				} else if (arr[i][j] == '?' && l != k) {
					f[i][j][l + 1] = max(f[i][j][l + 1], f[i][j][l] + 1);
				}
			}
		}
	}
	cout << f[n][m][k] << endl;
	return 0;
} 

F 千刀题

出现の问题

  1. 二分:因为边随着时间的流逝不会消失,只会增加,所以当 \(T'\) 满足要求时,所有 \(> T'\) 的答案也必定符合要求。

六种解法及获得分数(难度递增)

  1. \(m=8\) 暴搜每条边的出现情况,找到出现最晚的边,判断(\(20pts\)
  2. \(t\leq n \leq100\) 枚举答案 \(T\),判断(\(60pts\)
  3. \(s=1\) 二分答案 + 暴力 bfs 检验(\(70pts\)
  4. \(v=1\) 双向 bfs 优化(\(80pts\)
  5. 正解:只关心 V 中的点是否能被 S 中的点到达,不关心是哪一个点,所以初始时把所有 S 中的点都加入 bfs 队列

坑点

  1. \(T=0\) 时,可能符合要求
  2. 不保证 SV 无交集
  3. vis 数组和 ver 邻接表需要是全局变量,不可以开在函数内

正确代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
const int M = 1e6 + 10;

int n, m, S, V;
struct Node {
	int u, v, t;
} arr[M];
int s[N], v[N];
bool vis[N];
vector<int> ver[N];

bool check(int x) {
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; i ++) {
		ver[i].clear();
	}
	for (int i = 1; i <= m; i ++) {
		if (arr[i].t <= x) {
			ver[arr[i].u].push_back(arr[i].v);
			ver[arr[i].v].push_back(arr[i].u);
		}
	}
	queue<int> q;
	for (int i = 1; i <= S; i ++) {
		q.push(s[i]);
		vis[s[i]] = true;
	}
	while (!q.empty()) {
		int tmp = q.front();
		q.pop();
		for (auto i: ver[tmp]) {
			if (!vis[i]) {
				q.push(i);
				vis[i] = true;
			}
		}
	}
	for (int i = 1; i <= V; i ++) {
		if (!vis[v[i]]) {
			return false;
		}
	}
	return true;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i ++) {
		scanf("%d%d%d", &arr[i].u, &arr[i].v, &arr[i].t);
	}
	scanf("%d", &S);
	for (int i = 1; i <= S; i ++) {
		scanf("%d", &s[i]);
	}
	scanf("%d", &V);
	for (int i = 1; i <= V; i ++) {
		scanf("%d", &v[i]);
	}
	
	int l = 0, r = 1e9, ans = 0;
	while (l <= r) {
		int mid = (l + r) >> 1;
		if (check(mid)) {
			ans = mid;
			r = mid - 1;
		} else {
			l = mid + 1;
		}
	}
	cout << ans << endl;
	return 0;
} 
posted @ 2023-07-27 10:00  SuperUser777  阅读(23)  评论(0)    收藏  举报