牛客周赛 Round 81


A. 麻将入门

题意:给你三个数,判断是不是相等或者连续的三个数。

点击查看代码
void solve() {	
	int a, b, c;
	std::cin >> a >> b >> c;
	if ((a == b && b == c) || (a + 1 == b && b + 1 == c)) {
		std::cout << "Yes\n";
	} else {
		std::cout << "No\n";
	}
}

B. 数数入门

题意:给你一个数字金字塔,判断是不是每个a[i][j]都小于等于a[i+1][j]a[i+1][j+1]

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

    for (int i = 0; i + 1 < n; ++ i) {
    	for (int j = 0; j <= i; ++ j) {
    		if (a[i][j] > a[i + 1][j] || a[i][j] > a[i + 1][j + 1]) {
    			std::cout << "No\n";
    			return;
    		}
    	}
    }

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

C. 加法入门

题意:题意:给你一个数字金字塔,现在翻转了一个区间的数的位置,判断是不是每个a[i][j]都小于等于a[i+1][j]a[i+1][j+1]

发现翻转区间的数超过两层肯定不行,都在一层一定可以,考虑横跨两层的情况,那么要让下面的数翻上去后下面没有从上面翻下去的数,那么翻转总数要小于等于下面这层的数的个数。

点击查看代码
void solve() {
    i64 n;
    std::cin >> n;
    auto get = [&](i64 x) -> std::array<i64, 3> {
    	i64 l = 0, r = n;
    	while (l < r) {
    		i64 mid = l + r + 1 >> 1ll;
    		if (1 + mid * (mid + 1) / 2 <= x) {
    			l = mid;
    		} else {
    			r = mid - 1;
    		}
    	}

    	return {l, x - (1 + l * (l + 1) / 2) + 1, (1 + (l + 1) * (l + 2) / 2) - x};
    };

    i64 l, r;
    std::cin >> l >> r;
    auto a = get(l), b = get(r);
    if (a[0] == b[0] || (a[0] + 1 == b[0] && a[2] + b[1] <= b[0])) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

D. 中场撸猫

题意:给你一个n×n的矩阵,要你从每层选i个数构造一个数字金字塔,最多能构造几层。

每层都应该尽量选最小的一些数,那么可以对每一层数进行排序,然后下一场贪心的从小到大选数匹配上一场的。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector a(n, std::vector<int>(n));
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		std::cin >> a[i][j];
    	}
    	std::sort(a[i].begin(), a[i].end());
    }


    std::vector<int> last;
    last.push_back(a[0][0]);
    for (int i = 1; i < n; ++ i) {
    	std::vector<int> b;
    	int j = 0;
    	for (int k = 0; j < i && k < n; ++ k) {
    		if (a[i][k] >= last[j]) {
    			b.push_back(a[i][k]);
    			++ j;
    		}

    		if (b.size() == i) {
    			if (k == n - 1) {
    				std::cout << i << "\n";
    				return;
    			}
    			b.push_back(a[i][k + 1]);
    		}
    	}

    	if (j < i) {
    		std::cout << i << "\n";
    		return;
    	}

    	last = b;
    }

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

E. 建筑入门

题意:你要构造一个n层金字塔,每层都是一样的数,然后所有数字总和为k

正解是dp,但我爆搜过了,可能是数据水了。
搜索构造n层且需要总和为k,当前可选最大数为m的问题,加了一些剪枝。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    std::vector<i64> pre(k + 1);
    for (int i = 1; i <= k; ++ i) {
    	pre[i] = (i64)i * i + pre[i - 1];
    }
    std::vector<int> ans, a;
    auto dfs = [&](auto self, int n, int k, int m) -> void {
    	if (ans.size()) {
    		return;
    	}

    	if (n == 0 && k == 0) {
    		ans = a;
    		return;
    	}

    	if (n == 0 || k == 0 || m < n) {
    		return;
    	}

    	i64 sum = 0;
    	for (int i = n, x = m; i >= 1; -- i, -- x) {
    		sum += (i64)i * x;
    	}

    	if (sum < k) {
    		return;
    	}

    	sum = pre[n - 1];
    	int l = n, r = std::min(m, k / n);
    	while (l < r) {
    		int mid = l + r >> 1;
    		if (sum + (i64)mid * n >= k) {
    			r = mid;
    		} else {
    			l = mid + 1;
    		}
    	}

    	for (int i = l; i >= 1; -- i) {
    		a.push_back(i);
    		self(self, n - 1, k - i * n, i - 1);
    		a.pop_back();
    	}
    };

    dfs(dfs, n, k, k / n);

    if (ans.empty()) {
    	std::cout << -1 << "\n";
    	return;
    }

    std::reverse(ans.begin(), ans.end());
    for (auto & x : ans) {
    	std::cout << x << " \n"[ans.back() == x];
    }
}

F. 拆迁入门

题意:一个按数字大小顺序放置的数字金字塔,然后拿走了k个,如果一个位置下面两个都被拿走了,也会消失,问最后消失了多少。

存每一层连续的数字,然后每层拿最大的区间,计算对下一个区间的贡献。

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

    auto get = [&](i64 x) -> i64 {
    	i64 l = 0, r = n;
    	while (l < r) {
    		i64 mid = l + r + 1 >> 1ll;
    		if (1 + mid * (mid + 1) / 2 <= x) {
    			l = mid;
    		} else {
    			r = mid - 1;
    		}
    	}

    	return l;
    };

    std::set<std::pair<i64, i64>> s;
    std::sort(a.begin(), a.end());
    for (int i = 0; i < k; ++ i) {
    	int j = i;
    	i64 id = get(a[i]);
    	i64 l = a[i], r = a[i];
    	while (j + 1 < k && a[j + 1] == a[j] + 1 && get(a[j + 1]) == id) {
    		++ j;
    		++ r;
    	}

    	i = j;
    	s.insert({l, r});
    }

    auto insert = [&](i64 l, i64 r) -> void {
    	if (l == r) {
    		return;
    	}

    	i64 id = get(l);
    	i64 x = l - id, y = r - id - 1;
    	while (s.size()) {
    		auto pre = s.lower_bound({x, y});
	    	if (pre != s.begin()) {
	    		-- pre;
	    		if (pre->second >= x - 1 && get(pre->second) == get(x)) {
	    			x = std::min(x, pre->first);
	    			y = std::max(y, pre->second);
	    			s.erase(pre);
	    		} else {
	    			break;
	    		}
	    	} else {
	    		break;
	    	}
    	}
    	
    	while (s.size()) {
    		auto next = s.lower_bound({x, y});
	    	if (next != s.end()) {
	    		if (next->first <= y + 1 && get(next->first) == get(x)) {
	    			x = std::min(x, next->first);
	    			y = std::max(y, next->second);
	    			s.erase(next);
	    		} else {
	    			break;
	    		}
	    	} else {
	    		break;
	    	}
    	}

    	s.insert({x, y});
    };

    i64 ans = 0;
    while (s.size()) {
    	auto [l, r] = *s.rbegin(); 
    	s.erase({l, r});
    	// std::cout << l << " " << r << "\n";
    	ans += r - l + 1;
    	insert(l, r);
    }

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