#P4264. 第1题-银行的两类客户
-
1000ms
Tried: 2
Accepted: 1
Difficulty: 3
-
算法标签>双指针
第1题-银行的两类客户
解题思路
-
解析输入为整数序列(可能整行带双引号,如
"8 2 13";实现优先做字面量/替换解析)。 -
按奇偶分成两队列:
QueueA:奇数(普通客户),保持输入顺序。QueueB:偶数(VIP),整体一次性降序排序。
-
合并规则:循环执行“先最多取 3 个
QueueB,再取 1 个QueueA”;若某队列空,则将另一个队列剩余依既定顺序追加。 -
算法要点:线性分区 + 偶数部分降序排序 + 双指针按“3:1”节奏合并。
-
输出要求:最终整串用一对双引号包裹,与输入风格一致,如
"8 4 2 1 3"。
复杂度分析
-
设总数
n,偶数数目m:- 时间复杂度:分区
O(n)+ 排序偶数O(m log m)+ 合并O(n)→ 总计O(n + m log m) ≤ O(n log n)。 - 空间复杂度:两个队列与结果数组 →
O(n)。
- 时间复杂度:分区
代码实现
Python
# -*- coding: utf-8 -*-
# 题面功能写在外部函数;主函数只做输入输出
from ast import literal_eval
def process_customers(nums):
"""根据题意处理客户编号,返回处理顺序列表"""
queueA, queueB = [], []
for x in nums:
if x % 2 == 1:
queueA.append(x) # 奇数保持输入顺序
else:
queueB.append(x) # 偶数待降序
queueB.sort(reverse=True) # 偶数降序
i, j = 0, 0
res = []
# 两队列都非空时按 3:1 处理
while i < len(queueB) and j < len(queueA):
take = 0
while take < 3 and i < len(queueB):
res.append(queueB[i]); i += 1; take += 1
if j < len(queueA):
res.append(queueA[j]); j += 1
# 追加剩余
while i < len(queueB):
res.append(queueB[i]); i += 1
while j < len(queueA):
res.append(queueA[j]); j += 1
return res
def parse_input_line(s):
"""优先 literal_eval 解析可能带引号的整行"""
s = s.strip()
try:
val = literal_eval(s)
if isinstance(val, str):
tokens = val.strip().split()
elif isinstance(val, (list, tuple)):
return [int(x) for x in val]
else:
tokens = str(val).split()
except Exception:
tokens = s.replace('"', '').strip().split()
return [int(x) for x in tokens]
def main():
import sys
line = sys.stdin.readline()
nums = parse_input_line(line)
ans = process_customers(nums)
out = " ".join(map(str, ans))
# 按要求:整体用双引号包裹输出
print(f"\"{out}\"")
if __name__ == "__main__":
main()
Java
// 类名统一为 Main(ACM 风格)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.*;
public class Main {
// 按规则处理客户队列
public static List<Integer> processCustomers(List<Integer> nums) {
List<Integer> queueA = new ArrayList<>(); // 奇数:保持输入顺序
List<Integer> queueB = new ArrayList<>(); // 偶数:降序
for (int x : nums) {
if ((x & 1) == 1) queueA.add(x);
else queueB.add(x);
}
queueB.sort(Collections.reverseOrder());
int i = 0, j = 0;
List<Integer> res = new ArrayList<>();
while (i < queueB.size() && j < queueA.size()) {
int take = 0;
while (take < 3 && i < queueB.size()) {
res.add(queueB.get(i++));
take++;
}
if (j < queueA.size()) {
res.add(queueA.get(j++));
}
}
while (i < queueB.size()) res.add(queueB.get(i++));
while (j < queueA.size()) res.add(queueA.get(j++));
return res;
}
// 解析输入行:去除双引号后按空白切分
public static List<Integer> parseLine(String line) {
line = line.trim().replace("\"", " ");
String[] parts = line.trim().split("\\s+");
List<Integer> nums = new ArrayList<>();
for (String p : parts) {
if (p.length() == 0) continue;
nums.add(Integer.parseInt(p));
}
return nums;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
List<Integer> nums = parseLine(line);
List<Integer> ans = processCustomers(nums);
StringBuilder sb = new StringBuilder();
for (int k = 0; k < ans.size(); k++) {
if (k > 0) sb.append(' ');
sb.append(ans.get(k));
}
// 输出整体用双引号包裹
System.out.println("\"" + sb.toString() + "\"");
}
}
C++
// ACM 风格:功能在外部函数,主函数做输入输出
#include <bits/stdc++.h>
using namespace std;
// 根据规则生成处理顺序
vector<int> processCustomers(const vector<int>& nums) {
vector<int> A, B; // A: 奇数(保持输入顺序),B: 偶数(降序)
for (int x : nums) {
if (x % 2) A.push_back(x);
else B.push_back(x);
}
sort(B.begin(), B.end(), greater<int>()); // 偶数降序
vector<int> res;
size_t i = 0, j = 0;
while (i < B.size() && j < A.size()) {
int take = 0;
while (take < 3 && i < B.size()) { // 先取至多3个VIP
res.push_back(B[i++]);
++take;
}
if (j < A.size()) { // 再取1个普通
res.push_back(A[j++]);
}
}
// 余者追加
while (i < B.size()) res.push_back(B[i++]);
while (j < A.size()) res.push_back(A[j++]);
return res;
}
// 解析输入:替换双引号,stringstream 读取整数
vector<int> parseLine(const string& raw) {
string s = raw;
for (char &c : s) if (c == '\"') c = ' ';
stringstream ss(s);
vector<int> nums; int x;
while (ss >> x) nums.push_back(x);
return nums;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string line;
getline(cin, line); // 读取整行
vector<int> nums = parseLine(line);
vector<int> ans = processCustomers(nums);
// 输出整体用双引号包裹
cout << '"';
for (size_t k = 0; k < ans.size(); ++k) {
if (k) cout << ' ';
cout << ans[k];
}
cout << '"' << '\n';
return 0;
}
题目内容
银行有两类客户:普通客户(编号为奇数)和 VIP 客户(编号为偶数)。你需要设计一个程序,将客户编号按照以下规则分配到两个队列中:
QueueA 存储普通客户(奇数),按输入顺序排列。
QueueB 存储 VIP 客户(偶数),按编号从大到小排序。
最终处理顺序:
-
先处理 VIP 客户 (QueueB)
-
每处理 3 个 VIP 客户后,必须处理 1 个普通客户 (QueueA)
-
当其中一个队列为空时,处理剩余的客户。最终输出:按上述规则处理后的客户编号序列。
输入与输出
-
输入:一行正整数,表示客户编号列表(以空格分隔)。
-
输出:处理顺序的客户编号序列(以空格分隔,末尾无多余空格)
补充说明
-
QueueA(奇数):[1,3,9,11,13,15](保持输入顺序)。
-
QueueB(偶数):[8,2,4]→降序排序为[8,4,2]。
-
处理顺序:
- 处理 3 个 VIP:8,4,2。
- 处理 1 个普通客户: 1。
- QueueB 已空,处理 QueueA 剩余:3,9,11,13,15
样例1
输入
"8 2 1 3 9 4 11 13 15"
输出
"8 4 2 1 3 9 11 13 15"
本题属于以下题库,请选择所需题库进行购买