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