VP AtCoder Beginner Contest 380


A - 123233

模拟即可。

点击查看代码
void solve() {
    int cnt[10]{};
    int n;
    std::cin >> n;
    while (n) {
    	++ cnt[n % 10];
    	n /= 10;
    }

    for (int i = 1; i <= 3; ++ i) {
    	if (cnt[i] != i) {
    		std::cout << "No\n";
    		return;
    	}
    }

    std::cout << "Yes\n";
}

B - Hurdle Parsing

题意:给你一个字符串,用'|',分割了一些'-',问每一段'-'的个数是多少。

模拟。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    for (int i = 0; i + 1< s.size(); ++ i) {
    	int j = i + 1;
    	while (j < s.size() && s[j] == '-') {
    		++ j;
    	}

    	std::cout << j - i - 1 << " ";
    	i = j - 1;
    }
    std::cout << "\n";
}

C - Move Segment

题意:给你一个\(01\)串,把第\(k\)\(1\)的连通块移到前面\(1\)的后面。

模拟。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    std::string s;
    std::cin >> s;
    int cnt = s[0] == '1', last = -1;
    for (int i = 0; i < n; ++ i) {
    	if (s[i] == '0' && s[i + 1] == '1') {
    		++ cnt;
    		if (cnt == k) {
    			int j = i + 1;
    			++ last;
    			while (j < n && s[j] == '1') {
    				std::swap(s[j], s[last]);
    				++ j, ++ last;
    			}
    			break;
    		}
    	}

    	if (s[i] == '1') {
    		last = i;
    	}
    }

    std::cout << s << "\n";
}

D - Strange Mirroring

题意:对于一个字符串,每次把它大小写改变然后接到后面,重复\(10^{100}\)次,\(q\)次询问,每次问第\(k\)个字符。

模拟单个字符发现,每次长度是成倍数增长,第\(n + 2^in\)个地方一定是取反的,因为这个地方就是第一个字符变过来的,这提示我们找到\(k\)在的块,然后就变成了一个子问题,看要找多少次记录取反次数就行。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    int q;
    std::cin >> q;
    while (q -- ) {
    	i64 x;
    	std::cin >> x;
    	int cnt = 0;
    	while (x > n) {
    		i64 k = 1;
    		while ((__int128)k * n < x) {
    			k *= 2;
    		}

    		x -= (__int128)k * n / 2;
    		++ cnt;
    	}



    	char c = s[x - 1];
    	if (cnt & 1) {
    		c = c >= 'a' ? c - 32 : c + 32;
    	}

    	std::cout << c << " \n"[!q];
    }
}

E - 1D Bucket Tool

题意:\(n\)个格子每个格子的颜色为\(i\),有两种操作:

  1. \(x\)和所有与他相邻并且颜色相同的格子颜色都变成\(y\)
  2. 询问颜色为\(x\)的有多少个格子。

容易想到用并查集维护颜色相同的块,那么当改变一个格子颜色时,判断是不是要和这个块最左边位置减一的位置是不是同一个颜色,和这个块最右边位置加一的位置是不是同一个颜色。那么我们需要用并查集记录一个集合的颜色,个数,最左边位置和最右边位置。

点击查看代码
struct DSU {
	std::vector<int> fa, cnt;
	DSU(int _n) {
		fa.assign(_n + 1, 0);
		cnt.assign(_n + 1, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	void merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return;
		}
		fa[y] = x;
		cnt[x] += cnt[y];
		cnt[y] = 0;
	}

	int same(int x, int y) {
		return find(x) == find(y);
	}

	int size(int x) {
		return cnt[find(x)];
	}
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    DSU ds(n);
    std::vector<int> id(n + 1), min(n + 1), max(n + 1), cnt(n + 1, 1);
    std::iota(id.begin(), id.end(), 0);
    std::iota(min.begin(), min.end(), 0);
    std::iota(max.begin(), max.end(), 0);
    while (q -- ) {
    	int op;
    	std::cin >> op;
    	if (op == 1) {
    		int x, y;
    		std::cin >> x >> y;
    		if (id[ds.find(x)] != y) {
    			cnt[y] += ds.size(x);
    			cnt[id[ds.find(x)]] -= ds.size(x);
    			id[ds.find(x)] = y;
    			int l = min[ds.find(x)] - 1, r = max[ds.find(x)] + 1;
    			if (l && id[ds.find(l)] == y) {
    				min[ds.find(x)] = min[ds.find(l)];
    				ds.merge(x, l);
    			}

    			if (r <= n && id[ds.find(r)] == y) {
    				max[ds.find(x)] = max[ds.find(r)];
    				ds.merge(x, r);
    			}
    		}
    	} else {
    		int x;
    		std::cin >> x;
    		std::cout << cnt[x] << "\n";
    	}
    }
}

F - Exchange Game

题意:有两个人,第一个人有\(n\)张牌,第二个人有\(m\)张牌,桌子上还有\(k\)张牌。两个人轮流出牌,如果桌子上有一张牌小于当前这个人出的牌,那么当前这个人可以拿走这张牌。问第一个人能不能赢。

注意到\(n+m+k<=12\),想到爆搜,定义\(dfs(u, x, y), (u \in \{0, 1\})\)为出牌人为\(u\)第一个拥有牌的状态为\(x\),第二个为\(y\),这里的\(x,y\)都是二进制数,利用状压表示有没有某一张牌。那么每次枚举当前这个人出哪张牌和是否拿走某张牌。和\(sg\)函数一样,不能走为必败态,如果当前状态能走到一个必败态则是必胜态,否则时必败态。

点击查看代码
const int N = 1 << 12;

int f[2][N][N];
int a[12];
int n, m, k;

int dfs(int u, int x, int y) {
	if (f[u][x][y] != -1) {
		return f[u][x][y];
	}

	int c = ~(x | y);
	int res = 0;
	if (u == 0) {
		for (int i = 0; i < n + m + k; ++ i) {
			if (x >> i & 1) {
				res |= !dfs(u ^ 1, x - (1 << i), y);
				for (int j = 0; j < n + m + k; ++ j) {
					if ((c >> j & 1) && a[j] < a[i]) {
						res |= !dfs(u ^ 1, x - (1 << i) + (1 << j), y);
					}
				}
			}
		}
	} else {
		for (int i = 0; i < n + m + k; ++ i) {
			if (y >> i & 1) {
				res |= !dfs(u ^ 1, x, y - (1 << i));
				for (int j = 0; j < n + m + k; ++ j) {
					if ((c >> j & 1) && a[j] < a[i]) {
						res |= !dfs(u ^ 1, x, y - (1 << i) + (1 << j));
					}
				}
			}
		}
	}

	f[u][x][y] = res;
	return res;
}

void solve() {
    std::cin >> n >> m >> k;
    for (int i = 0; i < n + m + k; ++ i) {
    	std::cin >> a[i];
    }

    memset(f, -1, sizeof f);
    if (dfs(0, (1 << n) - 1, (1 << n + m) - (1 << n))) {
    	std::cout << "Takahashi\n";
    } else {
    	std::cout << "Aoki\n";
    }
}
posted @ 2025-01-20 22:02  maburb  阅读(18)  评论(0)    收藏  举报