Educational Codeforces Round 88 部分题解

A. Berland Poker

题意:

给定 \(n\) 张牌,其中有 \(m\) 张小丑牌,分成 \(k\) 份,记录每个人的小丑牌个数,求(最大个数-次大个数)的最大值。

思路:

贪心的想,使得最大个数尽可能大,并且次大个数尽可能小,接下来分类讨论:

①小丑牌个数\(\le\)手牌上限,\(m\le \frac{n}{k}\):此时可以让一个人拿完小丑牌,最大个数为 \(m\),次大个数为 \(0\),答案为 \(m\)

①小丑牌个数\(>\)手牌上限,\(m> \frac{n}{k}\):此时可以让一个人拿满小丑牌,剩下的 \(m-\frac{n}{k}\) 张小丑牌尽可能均分给剩下的人,使得次大个数最小,此时最大个数为 \(\frac{n}{k}\),次大个数为 \(\lceil\frac{m-\frac{n}{k}}{k-1}\rceil\),答案为 \(\frac{n}{k}-\lceil\frac{m-\frac{n}{k}}{k-1}\rceil\)

代码

点击查看代码
void solve() {
	int n, m,k;
	cin >> n >> m>>k;
	int p=min(m,n/k);
	int ans=p-(m-p+(k-2))/(k-1);
	cout<<ans<<endl;
}

B. New Theatre Square

题意:

给定一个黑白矩阵,1*1的格子代价为 \(x\),1*2的格子代价为 \(y\),求涂黑的最小代价。

思路:

贪心,分类讨论:

\(x*2\le y\):全部用1*1。

\(x*2> y\):能用1*2就用,其他的用1*1。

代码

点击查看代码
void solve() {
	int n, m,x,y;
	cin >> n >> m>>x>>y;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char c;
			cin>>c;
			a[i][j]=(c=='.');
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(j+1<=m){
				if(a[i][j]==a[i][j+1]&&a[i][j]==1){
					ans+=min(x*2,y);
					j++;
				}else{
					if(a[i][j]){
						ans+=x;
					}
				}
			}else{
				if(a[i][j]){
					ans+=x;
				}
			}
		}
	}
	cout<<ans<<endl;
}

C. Mixing Water

题意:

给定 \(h,c,t\),循环操作,加入一个 \(h\),加入一个 \(c\),求平均值最接近 \(t\) 的最少次数。

思路:

\(h\)\(c\) 的次数相等时,平均值为 \(\frac{h+c}{2}\),最少次数为 2。
\(h\)\(c\) 的次数不相等时,不妨设 \(h\) 的次数为 \(x+1\)\(c\) 的次数为 \(x\)
则平均值为 \(\frac{h\cdot (x+1)+c\cdot x}{2x+1}=\frac{h+c}{2}+\frac{h-c}{4x+2}\)
此函数为单调函数,我们可以直接计算或者二分得到最接近 \(t\) 的左右两个点,然后比较,得到最小值和最少次数。

代码

点击查看代码
void solve() {
	int n, m,x,y;
	cin >> n >> m>>x>>y;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char c;
			cin>>c;
			a[i][j]=(c=='.');
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(j+1<=m){
				if(a[i][j]==a[i][j+1]&&a[i][j]==1){
					ans+=min(x*2,y);
					j++;
				}else{
					if(a[i][j]){
						ans+=x;
					}
				}
			}else{
				if(a[i][j]){
					ans+=x;
				}
			}
		}
	}
	cout<<ans<<endl;
}

D. Yet Another Yet Another Task

题意:

给定数组,求(区间和-区间最大值)的最大值。

思路:

值域很小,直接枚举区间最大值 \(x\),然后遍历数组,使得选取区间最大值小于等于 \(x\),记录答案即可。

代码

点击查看代码
int a[N];
void solve() {
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i) cin >> a[i];
	int ans = 0;
	for (int m = -30; m <= 30; ++m) {
		int c0 = -INF, c1 = -INF, b = -INF;
		for (int x : a) {
			if (x > m) {
				c0 = c1 = -INF;
			} else if (x == m) {
				int t = max(c0, c1);
				if (t > -INF / 2) c1 = max(x, t + x);
				else c1 = x;
				c0 = -INF;
				b = max(b, c1);
			} else {
				if (c0 > -INF / 2) c0 = max(x, c0 + x);
				else c0 = x;
				if (c1 > -INF / 2) {
					c1 = c1 + x;
					b = max(b, c1);
				}
			}
		}
		if (b > -INF / 2) ans = max(ans, b - m);
	}
	cout << ans << endl;
}

E. Modular Stability

题意:

有多少个数组满足$ (((x \bmod a_1) \bmod a_2) \dots \bmod a_{k - 1}) \bmod a_k = (((x \bmod a_{p_1}) \bmod a_{p_2}) \dots \bmod a_{p_{k - 1}}) \bmod a_{p_k}$ 对任意排列 \(p\) 成立。

思路:

结论题/证明题
结论:题意条件等价于数组的最小值能够整除数组里的任意数。
然后用组合数计数即可。

代码

点击查看代码
void solve() {
	init();
	int n, k;
	cin >> n >> k;
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		int v = n / i;
		if (v >= k) {
			ans = (ans + C(v-1, k-1)) % mod;
		}
	}
	cout << ans << endl;
}
posted @ 2026-01-20 20:42  ptlks  阅读(1)  评论(0)    收藏  举报