{ }codelper
多重条件包含判断逻辑运算符P0167

快递价目表

快递公司根据箱子的重量和收件地区决定运费。
第一行给出海岛、山区这类偏远地区的个数 k,第二行给出 k 个偏远地区编号,用空格分开。
第三行给出箱子数 n,接下来 n 行每行给出一个箱子的收件地区编号、重量(克)和配送类型,用空格分开。
配送类型是普通配送 "N" 或加急配送 "X"。
基本运费由重量决定。
不超过 1,000g 为 3,500 韩元,超过 1,000g 且不超过 3,000g 为 4,000 韩元,超过 3,000g 且不超过 7,000g 为 5,000 韩元。
超过 7,000g 且不超过 15,000g 为 6,500 韩元,超过 15,000g 且不超过 25,000g 为 8,500 韩元。
超过 25,000g 的箱子不收。
如果收件地区编号与某个偏远地区编号相同,加 3,000 韩元。
只有当收件地区不是偏远地区且重量不超过 15,000g 时才能加急配送,此时加 2,000 韩元。
不能加急配送的箱子也不收。
按输入顺序每行输出一个箱子的运费,不收的箱子输出 "拒收"。
最后一行输出收下的箱子数和收下的箱子运费之和,用一个空格分开。

输入
1 ≤ k ≤ 100,1 ≤ n ≤ 1,000,地区编号是 1 到 999 的整数(前面不补 0),偏远地区编号互不相同,1 ≤ 重量 ≤ 40,000
输出
每个箱子的运费或 "拒收",最后一行是收下的箱子数和运费之和
样例 1 · stdin
3
12 305 7
7
12 1000 N
112 1001 N
305 3000 X
7 25000 N
50 15000 X
50 15001 X
9 25001 N
stdout
6500
4000
拒收
11500
8500
拒收
拒收
4 30500
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

第一个陷阱是判断是否为偏远地区的「包含」检查。
如果把第二行保留为字符串,用 Python "12" in line、JS/TS line.includes("12")、Java line.contains("12")、C# line.Contains("12")、C strstr 去找,找的是子串,所以 "112" 里的 "12" 也会被找到。
要把编号转成数字收集起来,再用 Python set 的 in、JS/TS Set.has、Java HashSet.contains、C# HashSet<int>.Contains、C++ unordered_set::count(C++20 用 contains)来判断。
C 没有集合,但编号是 1~999,所以一张 is_remote[编号] 表就是集合。
Craykon 对用 控制台.读数字() 读到的数字列表使用 列表.包含(r)。
列表里的数字和从行里切出的字符串("12")比较不会相等,所以要用 转数字() 统一。
第二个陷阱是重量区间。
多重条件从上往下只执行第一个为真的分支,所以从小区间开始用 <= 判断并用 else if(Python elif,Craykon 否则 如果)连起来,就不用再判断下端。
如果不写 else、只排列 if,500g 的箱子后面的 if 也都为真,运费会被覆盖成 8,500 韩元。
用 < 判断,恰好 1,000g 的箱子会跳到上一档。
第三,加急条件要求两个条件都为真:Python 是 not far and w <= 15000,其他七种语言是 !far && w <= 15000。
写成 || 的话,偏远地区的轻箱子也能加急。
Java 用 == 比较 "X" 问的是是否同一个对象而不是内容是否相同,所以要用 equals(C#、Python、JS、Craykon 的 == 比较的是内容)。

Pythonmain.py · 40 行
def base_fee(w):    # 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다    if w <= 1000:        return 3500    elif w <= 3000:        return 4000    elif w <= 7000:        return 5000    elif w <= 15000:        return 6500    elif w <= 25000:        return 8500    else:        return None  # 25,000g을 넘으면 받지 않는다  input()  # kremote = set(map(int, input().split()))  # 수로 바꾼 집합: "12"가 "112" 안에 있다고 착각하지 않는다n = int(input())accepted = 0total = 0for _ in range(n):    r, w, s = input().split()    r, w = int(r), int(w)    fee = base_fee(w)    far = r in remote    if fee is not None and far:        fee += 3000    if fee is not None and s == "X":        if not far and w <= 15000:  # 빠른 배송은 두 조건을 모두 지켜야 한다            fee += 2000        else:            fee = None    if fee is None:        print("拒收")    else:        print(fee)        accepted += 1        total += feeprint(accepted, total)
JavaScriptmain.js · 36 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");// 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다const baseFee = (w) => {  if (w <= 1000) return 3500;  else if (w <= 3000) return 4000;  else if (w <= 7000) return 5000;  else if (w <= 15000) return 6500;  else if (w <= 25000) return 8500;  else return null; // 25,000g을 넘으면 받지 않는다};// 수로 바꾼 Set: 줄 문자열에 includes를 쓰면 "12"가 "112" 안에서 찾아진다const remote = new Set(lines[1].trim().split(/\s+/).filter((x) => x !== "").map(Number));const n = Number(lines[2]);const out = [];let accepted = 0;let total = 0;for (let i = 0; i < n; i++) {  const [rText, wText, s] = lines[3 + i].trim().split(/\s+/);  const r = Number(rText);  const w = Number(wText);  let fee = baseFee(w);  const far = remote.has(r);  if (fee !== null && far) fee += 3000;  if (fee !== null && s === "X") {    if (!far && w <= 15000) fee += 2000; // 빠른 배송은 두 조건을 모두 지켜야 한다    else fee = null;  }  if (fee === null) out.push("拒收");  else {    out.push(String(fee));    accepted++;    total += fee;  }}out.push(`${accepted} ${total}`);console.log(out.join("\n"));
TypeScriptmain.ts · 37 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");// 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다const baseFee = (w: number): number | null => {  if (w <= 1000) return 3500;  else if (w <= 3000) return 4000;  else if (w <= 7000) return 5000;  else if (w <= 15000) return 6500;  else if (w <= 25000) return 8500;  else return null; // 25,000g을 넘으면 받지 않는다};// 수로 바꾼 Set: 줄 문자열에 includes를 쓰면 "12"가 "112" 안에서 찾아진다const remote = new Set(lines[1].trim().split(/\s+/).filter((x) => x !== "").map(Number));const n = Number(lines[2]);const out: string[] = [];let accepted = 0;let total = 0;for (let i = 0; i < n; i++) {  const [rText, wText, s] = lines[3 + i].trim().split(/\s+/);  const r = Number(rText);  const w = Number(wText);  let fee: number | null = baseFee(w);  const far = remote.has(r);  if (fee !== null && far) fee += 3000;  if (fee !== null && s === "X") {    if (!far && w <= 15000) fee += 2000; // 빠른 배송은 두 조건을 모두 지켜야 한다    else fee = null;  }  if (fee === null) out.push("拒收");  else {    out.push(String(fee));    accepted++;    total += fee;  }}out.push(`${accepted} ${total}`);console.log(out.join("\n"));
JavaMain.java · 51 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.HashSet;import java.util.Set; public class Main {    static final int REJECT = -1;     // 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다    static int baseFee(int w) {        if (w <= 1000) return 3500;        else if (w <= 3000) return 4000;        else if (w <= 7000) return 5000;        else if (w <= 15000) return 6500;        else if (w <= 25000) return 8500;        else return REJECT; // 25,000g을 넘으면 받지 않는다    }     public static void main(String[] args) throws Exception {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        in.readLine(); // k        Set<Integer> remote = new HashSet<>();        for (String c : in.readLine().trim().split("\\s+")) {            if (!c.isEmpty()) remote.add(Integer.parseInt(c));        }        int n = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        int accepted = 0;        long total = 0;        for (int i = 0; i < n; i++) {            String[] p = in.readLine().trim().split("\\s+");            int r = Integer.parseInt(p[0]), w = Integer.parseInt(p[1]);            int fee = baseFee(w);            boolean far = remote.contains(r);            if (fee != REJECT && far) fee += 3000;            if (fee != REJECT && p[2].equals("X")) { // 문자열은 ==가 아니라 equals로 비교한다                if (!far && w <= 15000) fee += 2000; // 빠른 배송은 두 조건을 모두 지켜야 한다                else fee = REJECT;            }            if (fee == REJECT) {                out.append("拒收\n");            } else {                out.append(fee).append('\n');                accepted++;                total += fee;            }        }        out.append(accepted).append(' ').append(total).append('\n');        System.out.print(out);    }}
C#Main.cs · 53 行
using System;using System.Collections.Generic;using System.Linq;using System.Text; class Program{    // 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다    static int? BaseFee(int w)    {        if (w <= 1000) return 3500;        else if (w <= 3000) return 4000;        else if (w <= 7000) return 5000;        else if (w <= 15000) return 6500;        else if (w <= 25000) return 8500;        else return null; // 25,000g을 넘으면 받지 않는다    }     static void Main()    {        Console.ReadLine(); // k        var remote = new HashSet<int>(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse));        int n = int.Parse(Console.ReadLine());        var sb = new StringBuilder();        int accepted = 0;        long total = 0;        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int r = int.Parse(p[0]), w = int.Parse(p[1]);            int? fee = BaseFee(w);            bool far = remote.Contains(r);            if (fee != null && far) fee += 3000;            if (fee != null && p[2] == "X")            {                if (!far && w <= 15000) fee += 2000; // 빠른 배송은 두 조건을 모두 지켜야 한다                else fee = null;            }            if (fee == null)            {                sb.Append("拒收\n");            }            else            {                sb.Append(fee.Value).Append('\n');                accepted++;                total += fee.Value;            }        }        sb.Append(accepted).Append(' ').Append(total).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 48 行
#include <iostream>#include <optional>#include <string>#include <unordered_set> // 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다std::optional<int> baseFee(int w) {    if (w <= 1000) return 3500;    else if (w <= 3000) return 4000;    else if (w <= 7000) return 5000;    else if (w <= 15000) return 6500;    else if (w <= 25000) return 8500;    else return std::nullopt; // 25,000g을 넘으면 받지 않는다} int main() {    int k, n;    std::cin >> k;    std::unordered_set<int> remote;    for (int i = 0; i < k; i++) {        int code;        std::cin >> code;        remote.insert(code);    }    std::cin >> n;    int accepted = 0;    long long total = 0;    for (int i = 0; i < n; i++) {        int r, w;        std::string s;        std::cin >> r >> w >> s;        std::optional<int> fee = baseFee(w);        bool far = remote.count(r) > 0; // C++20부터는 remote.contains(r)        if (fee && far) *fee += 3000;        if (fee && s == "X") {            if (!far && w <= 15000) *fee += 2000; // 빠른 배송은 두 조건을 모두 지켜야 한다            else fee.reset();        }        if (!fee) {            std::cout << "拒收\n";        } else {            std::cout << *fee << '\n';            accepted++;            total += *fee;        }    }    std::cout << accepted << ' ' << total << '\n';}
Cmain.c · 50 行
#include <stdio.h>#include <string.h> #define REJECT -1 /* 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다 */int base_fee(int w) {    if (w <= 1000) return 3500;    else if (w <= 3000) return 4000;    else if (w <= 7000) return 5000;    else if (w <= 15000) return 6500;    else if (w <= 25000) return 8500;    else return REJECT; /* 25,000g을 넘으면 받지 않는다 */} int main(void) {    /* 지역 번호는 1~999라서 번호를 칸 번호로 쓰는 표가 곧 "들어 있나" 검사다 */    static int is_remote[1000];    int k, n;    scanf("%d", &k);    for (int i = 0; i < k; i++) {        int code;        scanf("%d", &code);        is_remote[code] = 1;    }    scanf("%d", &n);    int accepted = 0;    long total = 0;    for (int i = 0; i < n; i++) {        int r, w;        char s[4];        scanf("%d %d %3s", &r, &w, s);        int fee = base_fee(w);        int far = is_remote[r];        if (fee != REJECT && far) fee += 3000;        if (fee != REJECT && strcmp(s, "X") == 0) {            if (!far && w <= 15000) fee += 2000; /* 빠른 배송은 두 조건을 모두 지켜야 한다 */            else fee = REJECT;        }        if (fee == REJECT) {            printf("拒收\n");        } else {            printf("%d\n", fee);            accepted++;            total += fee;        }    }    printf("%d %ld\n", accepted, total);    return 0;}
Craykonmain.cray · 65 行
// 아래 칸부터 차례로 묻는다: 앞 조건이 거짓일 때만 다음 조건을 보니 칸의 아래 끝은 따로 묻지 않는다기본요금(w){    如果 (w <= 1000)    {        返回 3500;    }    否则 如果 (w <= 3000)    {        返回 4000;    }    否则 如果 (w <= 7000)    {        返回 5000;    }    否则 如果 (w <= 15000)    {        返回 6500;    }    否则 如果 (w <= 25000)    {        返回 8500;    }    返回 -1; // 25,000g을 넘으면 받지 않는다} 控制台.读行(); // kremote = 控制台.读数字(); // 수 목록: 문자열 "12 305"에서 찾으면 "12"가 "112" 안에서도 찾아진다n = 控制台.读行().转数字();accepted = 0;total = 0;循环 (i = 0; i < n; i++){    칸 = 控制台.读行().分割();    r = 칸[0].转数字();    w = 칸[1].转数字();    fee = 기본요금(w);    far = remote.包含(r);    如果 (fee != -1 && far)    {        fee += 3000;    }    如果 (fee != -1 && 칸[2] == "X")    {        如果 (!far && w <= 15000)        {            fee += 2000;        }        否则        {            fee = -1;        }    }    如果 (fee == -1)    {        控制台.输出("拒收");    }    否则    {        控制台.输出(fee);        accepted += 1;        total += fee;    }}控制台.输出(accepted + " " + total);