0921

Done OI Start at: 2025-9-21 18:30 2.5 hour(s) Host: 64
#include <bits/stdc++.h>
using namespace std;
int main(){
	int n, minn = 1e6 + 1, a;
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> a;
		minn = min(minn, a);
	}
	cout << minn << endl;
}


解题思路 计算初始和:首先计算所有数字的初始和 tot。

计算减少量:对于每个数字,找到移除一位后能得到的最小值,并计算减少量(原始值减去最小值)。

排序减少量:将所有数字的减少量从大到小排序,决定操作顺序。

模拟操作:依次按照减少量从大到小的顺序操作每个数字,每次操作后总和减去该数字的减少量,并输出当前总和。

关键点 如何确定移除哪一位:使用贪心策略,从左到右扫描数字的每一位,如果发现某一位大于其后一位,则移除这一位(因为移除后后一位较小的数字会前移,使整体数字变小);如果没有这样的位,则移除最后一位。

个位数处理:个位数移除后直接变为0。

字符串处理:将数字转为字符串便于逐位处理,注意移除后字符串转换为数字时会自动去除前导0。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5 + 10;
ll n, tot, num[maxn];
char s[20];

int main() {
	cin >> n;
	for(int i = 1;i <= n; ++i) {
		cin >> (s + 1);
		ll len = strlen(s + 1), u = 0;
		for(int j = 1;j <= len; ++j) u = u * 10 + s[j] - '0';
		tot += u; 
		int del = 0;
		for(int j = 1;j <= len; ++j) 
			if(s[j] < s[j - 1]) {del = j - 1; break;}
			else if(j == len) {del = j; break;}
		ll v = 0;
		for(int j = 1;j <= len; ++j)
			if(j == del) continue;
			else v = v * 10 + s[j] - '0';
		
		num[i] = v - u;
	}
	sort(num + 1, num + n + 1);
	for(int i = 1;i <= n; ++i) {
		tot += num[i];
		cout << tot << '\n';
	}
	return 0;
}

题目解析 这个问题涉及模拟商场中顾客选择店铺的过程。每家店铺有一个容量 a_i 和一个服务时间 b_i。顾客会选择当前等待时间最短的店铺,如果等待时间相同,则选择编号较小的店铺。我们需要计算每家店铺最终的总人数(包括正在接受服务和排队的人)。

关键思路 初始分配:如果总人数 m 不超过所有店铺的容量之和,则顾客会优先选择编号小的店铺,直到分配完所有顾客。每个店铺的人数不会超过其容量。

二进制搜索:如果 m 超过容量之和,则需要分配额外的顾客。通过二进制搜索找到一个最小时间 ans,使得在时间 ans 内能够服务的所有顾客数量至少为 m。

分配顾客:根据二进制搜索的结果,计算在每个店铺中在时间 ans-1 内能服务的顾客数量,然后在时间 ans 内将剩余的顾客分配到符合条件的店铺中(即 ans 是 b_i 的倍数的店铺),分配时优先选择编号小的店铺。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
long long a[maxn], b[maxn];
int n;
long long m;
bool check(long long tim){
	long long sum = 0;
	for(int i = 1; i <= n; i++){
		sum += tim / b[i] * a[i];
	}
	return sum >= m;
}
int main(){
	long long sum = 0;
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		cin >> a[i] >> b[i];
		sum += a[i];
	}
	if(sum >= m){
		for(int i = 1; i <= n; i++){
			cout << 0 << " ";
		}
		return 0;
	}
	m -= sum;
	long long l = 1, r = 1e10, ans;
	while(l <= r){
		long long mid = (l + r) / 2;
		if(check(mid)){
			r = mid - 1;
			ans = mid;
		}else{
			l = mid + 1;
		}
	} 
	vector<long long>cnt(n+1), vis(n+1);
	for(int i = 1; i <= n; i++){
		if(ans % b[i] != 0)
			cnt[i] = ans / b[i] * a[i];
		else{
			vis[i] = 1;
			cnt[i] = (ans-1) / b[i] * a[i];
		}
		m -= cnt[i];
	}
	for(int i = 1; i <= n; i++){
		if(vis[i]){
			int now = min(m, 1ll*a[i]);
			cnt[i] += now;
			m -= now;
		}
	}
	for(int i = 1; i <= n; i++){
		cout << cnt[i] << " ";
	}
}

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, a[100009], sum, ans, b[2];
signed main() {
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		sum += a[i];
	}
	for(int i = 1; i <= n; i++) {
		if(a[i] * 3 > sum){
			cout << -1;
			return 0;
		}
		ans += a[i] / 2;
		if(a[i] / 2 > b[0])// b[0] 存放最大, b[1] 存放次大
			b[0] = a[i] / 2;
		if(b[0] > b[1])
			swap(b[0], b[1]);
	}
	while(true) { // 防止减完次大值之后,最大值 * 3 又大于 ans,所以进行循环 
		bool flag = 1;
		for(int i = 0; i <= 1; i++) {
			if(b[i] * 3 > ans) {
				flag = 0;
				int x = (3 * b[i] - ans + 1) / 2; 
				// 找到最小的 x 使得 b[i] * 3 <= ans,推不出此公式可以使用更复杂的分类讨论,并代值验算其正确性 
				b[i] -= x;
				ans -= x;
			}
		}
		if(flag)	break;
	}
	cout << min(ans / 3, sum / 9);
	return 0;
}


Status
Done
Rule
OI
Problem
4
Start at
2025-9-21 18:30
End at
2025-9-21 21:00
Duration
2.5 hour(s)
Host
Partic.
64