牛客周赛 Round 80


A. 棋盖放子

点击查看代码
void solve() {
    int x, y;
    std::cin >> x >> y;
    if (y > x) {
    	std::cout << "quit the competition!\n";
    } else {
    	std::cout << x - y << "\n";
    }
}

B. 训练参赛

题意:2n个人两人一组选n组,总价值为每组两个人的差的绝对值,求最小的价值。

可以看作一维上有2n个点,两个两个点连成线,让线的总长度最小。我们应该选相邻的两个。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(2 * n);
    for (int i = 0; i < 2 * n; ++ i) {
    	std::cin >> a[i];
    }

    std::sort(a.begin(), a.end());
    int ans = 0;
    for (int i = 1; i < 2 * n; i += 2) {
    	ans += a[i] - a[i - 1];
    }
    std::cout << ans << "\n";
}

C. 举手赢棋easy

题意:一个人01串,你可以改变一个位置的值,满足任何一个前缀的1都比0多。求有多少方案。

从前到后模拟一些,出现的第一个位置0比1多,那就必须要把前面的0变成1,然后更新下前缀,如果后面还有0比1多的情况,就无解了。
如果没有0比1多的情况,那么随便放。


D. 举手赢棋hard

题意:和C一样,但可以改变两个不同位置的值。

也是模拟一下,记录每个0比1多的位置到上一次0比1多的位置的0的个数,可以看作以这样的位置分段。然后记录有几个这样的位置。如果大于两个,则答案为0。如果有两个,则可以在第一段的0里选一个和第二段的0里选一个,也可以在第一段的0里选两个。如果有一个,则可以在第一段0里选一个和在其他位置选任意一个,或者在第一段里选两个。如果没有这样的位置,答案是n(n1)/2, 即任意两个位置。

点击查看代码
void solve() {
    i64 n;
    std::cin >> n;
    std::string s;
    std::cin >> s;
    i64 sum = 0, cnt = 0, cnt1[2]{}, flag = 0;
    for (int i = 0; i < n; ++ i) {
    	sum += s[i] == '1' ? 1 : -1;
    	cnt += s[i] == '0';

    	if (sum < 0) {
    		if (flag < 2) {
    			cnt1[flag] = cnt;
    		}
    		++ flag;
    		cnt = 0;
    		sum += 2;
    	}
    }

    if (flag > 2) {
    	std::cout << 0 << "\n";
    } else if (flag == 2) {
    	std::cout << cnt1[0] * (cnt1[0] - 1) / 2 + cnt1[0] * cnt1[1] << "\n";
    } else if (flag == 1) {
    	std::cout << cnt1[0] * (n - cnt1[0]) + cnt1[0] * (cnt1[0] - 1) / 2 << "\n";
    } else if (flag == 0) {
    	std::cout << n * (n - 1) / 2 << "\n";
    }
}

E. 公平对局

题意:给你一个围棋局面,求放一个黑棋最多可以吃多少白棋。

遍历每个白棋的联通块,如果这个联通块只有一口气,那么唯一和它连接的空格可以吃掉这个联通块,把贡献加到这个空格上去。最后取每个空格可以吃掉白棋的最大值就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> s[i];
    }

    const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    int size;
    std::set<std::pair<int, int>> set;
    std::vector st(n, std::vector<int>(n));
    auto dfs = [&](auto self, int x, int y) -> void {
    	++ size;
    	st[x][y] = 1;
    	for (int i = 0; i < 4; ++ i) {
    		int nx = x + dx[i], ny = y + dy[i];
    		if (nx < 0 || nx >= n || ny < 0 || ny >= n) {
    			continue;
    		}

    		if (s[nx][ny] == '.') {
    			set.insert({nx, ny});
    			continue;
    		}

    		if (st[nx][ny] || s[nx][ny] == '#') {
    			continue;
    		}

    		self(self, nx, ny);
    	}
    };

    std::vector sum(n, std::vector<int>(n));
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		if (!st[i][j] && s[i][j] == '*') {
    			size = 0;
    			set.clear();
    			dfs(dfs, i, j);
    			if (set.size() == 1) {
    				auto [x, y] = *set.begin();
    				sum[x][y] += size;
    			}
    		}
    	}
    }

    int ans = 0;
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		ans = std::max(ans, sum[i][j]);
    	}
    }

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

F. 训练参赛(二)

神秘构造,看G过的人多就去写G了,结果写红温了就没时间写这题了。
待补。


G. 不公平对局

题意:两个人每回合有概率吃掉对方一个棋子,最先吃到n格棋子的人输,问第一个人赢的概率是多少。

dp方程还是很好想的,不过没想到有一方吃到n棋子就少了一种转移。赛时一直wa直接红温。
转移方程为fi,j=fi1,j×p1(1p2)+fi,j1×(1p1)p2+fi1,j1×p1p2+fi,j×(1p1)(1p2)
发现右边也有fi,j,移相整理得:fi,j=fi1,j×p1(1p2)+fi,j1×(1p1)p2+fi1,j1×p1p21(1p1)(1p2)
就是考虑每种情况就行了,还是很简单的。不过当i=nj=n时,对局不会继续了,所以fn,j不会被fn,j1转移过来,fi,n不会被fi1,n转移过来。赛时一直没想到这点,直接调红温。

点击查看代码
void solve() {
    int n, a1, b1, a2, b2;
    std::cin >> n >> a1 >> b1 >> a2 >> b2;
    Z p1 = (Z)a1 / b1, p2 = (Z)a2 / b2;
    Z p3 = 1 / (1 - (1 - p1) * (1 - p2));

    if (a1 == b1 && a2 == b2) {
    	std::cout << 0 << "\n";
    	return;
    }

    std::vector f(n + 1, std::vector<Z>(n + 1));
    for (int i = 0; i <= n; ++ i) {
    	for (int j = 0; j <= n; ++ j) {
    		if (i == 0 && j == 0) {
    			f[i][j] = 1;
    		} else  {
    			if (j != n && i && p2 != 1) {
    				f[i][j] += f[i - 1][j] * p1 * (1 - p2);
    			}

    			if (i != n && j && p1 != 1) {
    				f[i][j] += f[i][j - 1] * (1 - p1) * p2;
    			}

    			if (i && j) {
    				f[i][j] += f[i - 1][j - 1] * p1 * p2;
    			}

    			f[i][j] = f[i][j] * p3;
    		}
    	}
    }

    Z ans = 0;
    for (int i = 0; i < n; ++ i) {
    	ans += f[i][n];
    }

    std::cout << ans << "\n";
}
posted @   maburb  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示