一、题目描述
云服务提供商会记录客户使用服务的计费日志。现在你需要根据这些日志为客户计算话单总费用。
日志记录包括:
- 时间戳(长度为 10 的字符串)
- 客户标识(长度为 1~16 的字符串)
- 计费因子(长度为 1~16 的字符串)
- 计费时长(整数范围为 0~100,超出视为非法并置为 0)
此外还提供一张计费因子单价表,未给出的因子视为单价为 0。
特殊规则:
- 同一客户 同一时间戳 同一计费因子 的记录只计一次,以首次记录为准。
你需要输出每个客户的总话单费用,并按客户标识的字典序升序输出。
二、输入描述
第一行:n 表示日志条数
接下来的 n 行:每行格式为 "时间戳,客户标识,计费因子,计费时长"
下一行:m 表示计费因子单价数
接下来 m 行:每行格式为 "计费因子,单价"
三、输出描述
每行一个客户,格式为:
客户名,总费用
按客户标识升序输出。
四、样例输入输出
输入示例:
5
1627845600,client1,factorA,10
1627845605,client2,factorB,15
1627845610,client1,factorA,5
1627845615,client1,factorB,8
1627845620,client2,factorB,20
2
factorA,5
factorB,7
输出示例:
client1,131
client2,245
说明:
-
client1:
- factorA:10 + 5 = 15,单价 5 → 15×5=75
- factorB:8,单价 7 → 8×7=56
- 总计:75 + 56 = 131
-
client2:
- factorB:15 + 20 = 35,单价 7 → 35×7 = 245
五、解题思路分析
- 去重处理:需要剔除重复记录,即:客户名 + 时间戳 + 计费因子 相同的记录只取第一个。
- 合法性检查:时长必须在
[0, 100]
范围,非法按0
处理。 - 单价匹配:若找不到对应的计费因子,则按
0
处理。 - 客户费用计算:统计每个客户所有有效记录对应的费用总和。
- 排序输出:按客户名字典序升序输出。
六、C实现源码详解(完整)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_N 1000 // 日志最大数量
#define MAX_M 1000 // 计费因子最大数量
#define MAX_LEN 100 // ID 字符串最大长度
#define MAX_CLIENTS 1000 // 客户数量最大值
#define MAX_FACTORS 100 // 计费因子种类最大值
// 客户记录结构体:包含客户ID、计费因子ID、累计使用时长
typedef struct {
char client_id[MAX_LEN]; // 客户唯一标识
char factor_id[MAX_LEN]; // 计费因子唯一标识
int total_duration; // 使用总时长
} ClientRecord;
// 因子价格结构体:记录每个因子的价格
typedef struct {
char factor_id[MAX_LEN]; // 因子ID
int price; // 因子的单价
} FactorPrice;
ClientRecord records[MAX_CLIENTS * MAX_FACTORS]; // 所有客户因子组合的记录
int record_count = 0; // 当前记录条数
FactorPrice prices[MAX_FACTORS]; // 存储所有计费因子的价格
int price_count = 0; // 当前因子数量
// 根据客户ID和因子ID查找对应记录在数组中的索引位置,若不存在返回 -1
int find_record_index(const char* client_id, const char* factor_id) {
for (int i = 0; i < record_count; i++) {
if (strcmp(records[i].client_id, client_id) == 0 &&
strcmp(records[i].factor_id, factor_id) == 0) {
return i; // 找到返回索引
}
}
return -1; // 未找到
}
// 获取某个因子的单价,若找不到返回 0
int get_factor_price(const char* factor_id) {
for (int i = 0; i < price_count; i++) {
if (strcmp(prices[i].factor_id, factor_id) == 0) {
return prices[i].price; // 返回对应单价
}
}
return 0; // 未定义价格时按0处理
}
int main() {
int n;
scanf("%d\n", &n); // 读取日志记录数(n 行)
char line[200]; // 用于存储一行输入
for (int i = 0; i < n; i++) {
fgets(line, sizeof(line), stdin); // 读取一行日志数据
// 分割字符串,依次提取日志ID、客户ID、因子ID、时长
char* token = strtok(line, ",");
char log_id[MAX_LEN], client_id[MAX_LEN], factor_id[MAX_LEN];
int duration;
strcpy(log_id, token); // 日志ID
token = strtok(NULL, ",");
strcpy(client_id, token); // 客户ID
token = strtok(NULL, ",");
strcpy(factor_id, token); // 因子ID
token = strtok(NULL, ",");
duration = atoi(token); // 时长
// 若时长不合法(负值或超过100),设为0
if (duration < 0 || duration > 100) duration = 0;
// 查找该客户因子的记录
int idx = find_record_index(client_id, factor_id);
if (idx != -1) {
// 已有记录,直接累计时长
records[idx].total_duration += duration;
} else {
// 没有记录,新建一条
strcpy(records[record_count].client_id, client_id);
strcpy(records[record_count].factor_id, factor_id);
records[record_count].total_duration = duration;
record_count++; // 记录数加一
}
}
int m;
scanf("%d\n", &m); // 读取因子价格的条数
for (int i = 0; i < m; i++) {
fgets(line, sizeof(line), stdin); // 读取一行因子信息
char* token = strtok(line, ",");
strcpy(prices[i].factor_id, token); // 因子ID
token = strtok(NULL, ",");
prices[i].price = atoi(token); // 对应价格
price_count++;
}
// 用于记录已处理过的客户,防止重复统计
char processed_clients[MAX_CLIENTS][MAX_LEN];
int processed_count = 0;
for (int i = 0; i < record_count; i++) {
int already_processed = 0;
// 判断该客户是否已经处理过
for (int j = 0; j < processed_count; j++) {
if (strcmp(processed_clients[j], records[i].client_id) == 0) {
already_processed = 1;
break;
}
}
if (already_processed) continue; // 已处理,跳过
// 标记为已处理
strcpy(processed_clients[processed_count++], records[i].client_id);
int total_cost = 0; // 该客户总费用
// 累计该客户所有因子的费用
for (int j = 0; j < record_count; j++) {
if (strcmp(records[j].client_id, records[i].client_id) == 0) {
int price = get_factor_price(records[j].factor_id);
total_cost += records[j].total_duration * price;
}
}
// 输出客户ID与其总费用
printf("%s,%d\n", records[i].client_id, total_cost);
}
return 0; // 程序结束
}
七、复杂度分析
- 时间复杂度:
- 去重处理 + 数据读取: O ( n ) O(n) O(n)
- 因子价格映射: O ( m ) O(m) O(m)
- 费用计算: O ( n ) O(n) O(n)
- 排序输出: O ( k log k ) O(k \log k) O(klogk)(k 为客户数)
- 空间复杂度: O ( n + m ) O(n + m) O(n+m)