比赛链接:

https://vjudge.net/contest/505856

A - String

exkmp,kmp树

B - Dragon slayer

题意:

\(n * m\) 的地图中,有 \(k\) 堵墙,施展一次魔法可以消除一堵墙,问从起点能够到达终点,最少消除多少堵墙。

思路:

数据范围小,爆搜或者状压(还没补)。
爆搜思路:
因为是在格子中走,所以将地图扩大两倍,在点上走,然后二进制枚举所有状态,将没有被破坏的墙添加到地图中,取一个最小的值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1};
void solve(){
	LL n, m, k;
	cin >> n >> m >> k;
	n = n * 2, m = m * 2;
	LL sx, sy, tx, ty;
	cin >> sx >> sy >> tx >> ty;
	sx = sx * 2 + 1, sy = sy * 2 + 1;
	tx = tx * 2 + 1, ty = ty * 2 + 1;
	vector <LL> x(k), y(k), X(k), Y(k);
	for (int i = 0; i < k; i ++ ){
		cin >> x[i] >> y[i] >> X[i] >> Y[i];
		x[i] *= 2, y[i] *= 2;
		X[i] *= 2, Y[i] *= 2;
	}
	LL ans = 20;
	bool ok = false;
	vector < vector<LL> > v(n + 1, vector<LL>(m + 1, 0));
	vector < vector<LL> > a(n + 1, vector<LL>(m + 1, -1));
	function<void(LL, LL)> dfs = [&] (LL x, LL y){
		if (x == tx && y == ty){
			ok = true;
			return;
		}
		v[x][y] = 1;
		for (int i = 0; i < 4; i ++ ){
			LL nx = x + dx[i], ny = y + dy[i];
			if (nx < 0 || ny < 0 || nx > n || ny > m) continue;
			if (v[nx][ny]) continue;
			if (~a[nx][ny]) continue;
			dfs(nx, ny);
		}
	};
	for (int s = 0; s < (1 << k); s ++ ){
		LL t = s, cnt = 0;
		for (int i = 0; i < k; i ++ , t >>= 1 ){
			LL tt = t & 1;
			if (!tt){
				for (int p = x[i]; p <= X[i]; p ++ )
					for (int q = y[i]; q <= Y[i]; q ++ )
						a[p][q] = i;
			}
			cnt = cnt + tt;
		}
		if (cnt >= ans){  //破坏的墙的数量大于已知答案,所以没必要进行搜索了
			for (int i = 0; i <= n; i ++ )
				for (int j = 0; j <= m; j ++ )
					v[i][j] = 0, a[i][j] = -1;
			continue;
		}
		ok = false;
		dfs(sx, sy);
		if (ok){
			ans = min(ans, cnt);
		}
		for (int i = 0; i <= n; i ++ )
			for (int j = 0; j <= m; j ++ )
				v[i][j] = 0, a[i][j] = -1;
	}
	cout << ans << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

C - Backpack

题意:

\(n\) 个物品和一个容量为 \(m\) 的背包,第 \(i\) 件物品的体积为 \(v\),价值为 \(w\),物品的价值之和为它们的价值的异或和,问是否存在一种方案使得背包装满,若有,输出装满时的最大价值。

思路:

以体积作为第一维,异或值作为第二维,不好求最大的异或值,所以反一下。
\(dp[i][j]\) 为异或值为 i 时,体积为 \(j\) 的方案。
得到转移方程 \(dp[i][j] = dp[i][j]\) | \(dp[i\) ^ \(w][j - v]\)
体积那一维可以通过 \(bitset\) 去优化。
通过滚动数组对空间进行了优化。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n, m;
	cin >> n >> m;
	bitset <1030> f[1030], g[1030];
	f[0][0] = 1;
	for (int i = 0; i < n; i ++ ){
		LL v, w;
		cin >> v >> w;
		for (int j = 0; j < 1024; j ++ )  //体积转移
			g[j] = f[j] << v;
		for (int j = 0; j < 1024; j ++ )  //异或值转移
			f[j] |= g[j ^ w];
	}
	for (int j = 1023; j >= 0; j -- ){
		if (f[j][m]){
			cout << j << "\n";
			return;
		}
	}
	cout << "-1\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

I - Laser

模拟

K - Random

题意:

\(n\) 个在 [0, 1] 范围的随机数。对它们进行 \(m\) 次操作,每次有 \(\frac{1}{2}\) 的几率删除其中的最大值,有 \(\frac{1}{2}\) 的几率删除其中的最小值。问最后剩余的值之和为多少。

思路:

特殊情况,全是 0.5,删除了 \(m\) 个,那剩下的就是 \(\frac{n - m}{2}\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 1e9 + 7;
LL qp(LL a, LL k, LL p){
	LL ans = 1;
	while (k){
		if (k & 1) ans = ans * a % p;
		k >>= 1;
		a = a * a % p;
	}
	return ans;
}
LL inv(LL x){
	return qp(x, mod - 2, mod);
}
void solve(){
	LL n, m;
	cin >> n >> m;
	cout << (n - m) * inv(2) % mod << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

L - Alice and Bob

题意:

黑板上有 \(n\) 种数,第 \(i\) 种数有 \(a_i\) 个,每回合 \(Alice\) 会将数分成两个集合,然后 \(Bob\) 删除其中一个集合中的数,并让另一个集合中的数全部减去 1,当有一个数字为 0 时 \(Alice\) 获胜,若数字无法再分,那么 \(Bob\) 获胜。

思路:

\(Alice\) 的必胜态出发,当它有 1 个 0 的时候获胜,有两个 1 的时候也可以获胜,四个 2 的时候获胜...以此类推下去。
所以可以反向操作,每次让第 \(i\) 个数加上 \(i + 1\) 的数的一半的量,如果可以得到 0,说明 \(Alice\) 获胜。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	cin >> n;
	vector <LL> a(n + 1);
	for (int i = 0; i <= n; i ++ )
		cin >> a[i];
	for (int i = n - 1; i >= 0; i -- )
		a[i] += a[i + 1] / 2;
	cout << (a[0] ? "Alice" : "Bob") << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}
posted on 2022-07-20 20:36  Hamine  阅读(189)  评论(0编辑  收藏  举报