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串,把第k1的连通块移到前面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

题意:对于一个字符串,每次把它大小写改变然后接到后面,重复10100次,q次询问,每次问第k个字符。

模拟单个字符发现,每次长度是成倍数增长,第n+2in个地方一定是取反的,因为这个地方就是第一个字符变过来的,这提示我们找到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{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 @   maburb  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示