{ }codelper
引数リストのコピーリストの並べ替えP0333

審査点をいくつでも受け取る関数

体操大会の演技の点数を求める関数 点数(難度, 切り捨て, 審査点たち) を作る。
難度 d と切り捨て数 k は必ず受け取り、その後ろの審査点はいくつでも受け取る。
関数は受け取った審査点のうち最も低い k 個と最も高い k 個を捨て、残った点の合計に d を掛けた値を返す。
同じ点が複数あっても、低い側から k 個、高い側から k 個だけを捨てる。
残る点がなければ合計は 0 である。
演技ごとにこの関数を二回呼ぶ。
正式点はすべての審査員の点を渡して 点数(d, k, s1, s2, …, sm) で求める。
主審点は行の先頭に書かれた二人の審査員(主審)の点だけを渡し、何も捨てずに 点数(d, 0, s1, s2) で求める。
一行目に演技の数 q が与えられる。
続く q 行に、演技ごとに d、k、そして審査点 s1, s2, …, sm が空白一つで区切って与えられる。
審査員の数 m は行ごとに違うことがあり、別には与えられない。
演技ごとに一行に正式点と主審点をこの順に空白一つで区切って出力せよ。
採点は出力だけを見るので、関数をどう作ったかは検査しない。
それでも、いくつでも受け取れる引数(その構文がない言語ではリストや配列一つ)を持つ関数を一つ作り、二回呼ぶ方法で解いてみよう。

入力
1 ≤ q ≤ 1,000。
1 ≤ d ≤ 10。
2 ≤ m ≤ 100。
0 ≤ k かつ 2 × k ≤ m。
0 ≤ 審査点 ≤ 100(すべて整数)
出力
q 行、各行に正式点と主審点
例 1 · stdin
3
3 1 9 7 8 10
2 0 5 6 7
1 1 4 100
stdout
51 48
36 22
0 104
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

いくつでも受け取る引数の書き方は言語ごとに違います。
Python def score(d, k, *scores)、JS function score(d, k, ...scores)、TS ...scores: number[]、Java static long score(int d, int k, int... scores)、C# static long Score(int d, int k, params int[] scores) で、一つの関数に一度だけ使えます。
JS・TS・Java・C# では必ず最後の引数でなければならず、Python は *scores の後ろに名前でだけ渡せる引数をさらに書けます(落とし穴 ③)。
C の ...(stdarg.h)は受け取った個数が分からず、配列を展開して渡すこともできないので、(const int *scores, int m) のように配列と個数を受け取り、C++ は std::vector<int> で受け取って score(d, 0, {s[0], s[1]}) のように波かっこでまとめて渡します。
Craykon にはこの構文がないのでリスト一つで受け取り、点数(d, 0, [s[0], s[1]]) のように呼びます。
呼ぶ側も違います。
Python の score(*nums) と JS の score(...nums) はリストを展開して、先頭の二つを d と k に、残りを scores に入れます。
TS は score(...nums) を拒みます(TS2556:展開したものが d と k の位置にいくつ入るか分からないため)。
そこで score(d, k, ...nums.slice(2)) と、残余引数の位置だけ展開します。
Java と C# は配列をそのまま渡せます。
落とし穴 ① 受け取ったものがコピーかどうかは言語ごとに違います。
Python の *scores は新しいタプル、JS・TS の ...scores は新しい配列なので、関数の中で並べ替えても呼んだ側はそのままです。
しかし Java の int... と C# の params に配列を渡すと、コピーせずにその配列をそのまま受け取ります。
Craykon のリストも同じです。
関数の中でそのまま並べ替えると呼んだ側の配列の順番が変わり、あとで s[0]、s[1] で取り出した主審点が最も低い二つの点になります(例の一行目の 48 が 45 になります)。
scores.clone()、(int[])scores.Clone()、Craykon scores.部分リスト(0, scores.個数) でコピーを並べ替えます。
C++ は vector を値で受け取ればコピーです。
② Python の *scores はタプルなので scores.sort() がありません(AttributeError)。
sorted(scores) を使います。
③ Python で def score(d, *scores, k=0) のように *scores の後ろに書いた引数は、名前をつけないと渡せません。
位置で渡した k は審査点に混ざります。
④ 捨てたあとに残る範囲を Python の ordered[k:-k] と書くと、k が 0 のとき [0:0] で空のリストになります。
ordered[k:len(ordered) - k] と書きます。
⑤ JS・TS の sort() は比較関数を渡さないと数も文字列の順で並べるので、10 が 9 より、100 が 20 より前に来ます。
sort((a, b) => a - b) と書きます。

Pythonmain.py · 20 行
import sys  def score(d, k, *scores):    """난도 d와 버림 k는 꼭 받고, 심사 점수는 몇 개든 받는다(scores는 튜플)."""    ordered = sorted(scores)  # 튜플은 고칠 수 없으니 정렬한 새 목록을 만든다    kept = ordered[k:len(ordered) - k]  # [k:-k]는 k가 0일 때 빈 목록이 된다    return d * sum(kept)  lines = sys.stdin.read().split("\n")q = int(lines[0])out = []for i in range(1, q + 1):    nums = list(map(int, lines[i].split()))    d, k = nums[0], nums[1]    official = score(*nums)  # 목록을 펼쳐 넘긴다: 앞의 둘은 d와 k로, 나머지는 scores로    head = score(d, 0, nums[2], nums[3])  # 주심 두 명만 따로 넘긴다    out.append(f"{official} {head}")print("\n".join(out))
JavaScriptmain.js · 19 行
// 난도 d와 버림 k는 꼭 받고, 심사 점수는 몇 개든 받는다(...scores는 새 배열)function score(d, k, ...scores) {  scores.sort((a, b) => a - b); // 비교 함수가 없으면 문자열 순서로 정렬된다  let sum = 0;  for (let i = k; i < scores.length - k; i++) sum += scores[i];  return d * sum;} const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const out = [];for (let i = 1; i <= q; i++) {  const nums = lines[i].trim().split(/\s+/).map(Number);  const [d, k] = nums;  const official = score(...nums); // 배열을 펼쳐 넘긴다: 값이 복사되므로 nums는 그대로다  const head = score(d, 0, nums[2], nums[3]); // 주심 두 명만 따로 넘긴다  out.push(official + " " + head);}console.log(out.join("\n"));
TypeScriptmain.ts · 22 行
import { readFileSync } from "node:fs"; // 난도 d와 버림 k는 꼭 받고, 심사 점수는 몇 개든 받는다(...scores는 새 배열)function score(d: number, k: number, ...scores: number[]): number {  scores.sort((a, b) => a - b); // 비교 함수가 없으면 문자열 순서로 정렬된다  let sum = 0;  for (let i = k; i < scores.length - k; i++) sum += scores[i];  return d * sum;} const lines: string[] = readFileSync(0, "utf8").split("\n");const q: number = Number(lines[0]);const out: string[] = [];for (let i = 1; i <= q; i++) {  const nums: number[] = lines[i].trim().split(/\s+/).map(Number);  const [d, k] = nums;  // score(...nums)는 d와 k 자리에 몇 개가 들어갈지 몰라 TS가 막는다: 나머지 매개변수 자리만 펼친다  const official: number = score(d, k, ...nums.slice(2));  const head: number = score(d, 0, nums[2], nums[3]); // 주심 두 명만 따로 넘긴다  out.push(official + " " + head);}console.log(out.join("\n"));
JavaMain.java · 32 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.Arrays; public class Main {    // 난도 d와 버림 k는 꼭 받고, 심사 점수는 몇 개든 받는다(int...은 맨 뒤에만 쓸 수 있다)    static long score(int d, int k, int... scores) {        // 배열을 그대로 넘겨받으면 부른 쪽 배열과 같은 것이다: 복사본을 정렬한다        int[] ordered = scores.clone();        Arrays.sort(ordered);        long sum = 0;        for (int i = k; i < ordered.length - k; i++) sum += ordered[i];        return d * sum;    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int q = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int line = 0; line < q; line++) {            String[] parts = in.readLine().trim().split("\\s+");            int d = Integer.parseInt(parts[0]), k = Integer.parseInt(parts[1]);            int[] s = new int[parts.length - 2];            for (int i = 0; i < s.length; i++) s[i] = Integer.parseInt(parts[i + 2]);            long official = score(d, k, s);        // 배열을 통째로 넘긴다            long head = score(d, 0, s[0], s[1]);   // 주심 두 명만 따로 넘긴다            out.append(official).append(' ').append(head).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 33 行
using System;using System.Text; class Program{    // 난도 d와 버림 k는 꼭 받고, 심사 점수는 몇 개든 받는다(params는 맨 뒤에만 쓸 수 있다)    static long Score(int d, int k, params int[] scores)    {        // 배열을 그대로 넘겨받으면 부른 쪽 배열과 같은 것이다: 복사본을 정렬한다        int[] ordered = (int[])scores.Clone();        Array.Sort(ordered);        long sum = 0;        for (int i = k; i < ordered.Length - k; i++) sum += ordered[i];        return d * sum;    }     static void Main()    {        int q = int.Parse(Console.ReadLine());        var sb = new StringBuilder();        for (int line = 0; line < q; line++)        {            string[] parts = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int d = int.Parse(parts[0]), k = int.Parse(parts[1]);            int[] s = new int[parts.Length - 2];            for (int i = 0; i < s.Length; i++) s[i] = int.Parse(parts[i + 2]);            long official = Score(d, k, s);        // 배열을 통째로 넘긴다            long head = Score(d, 0, s[0], s[1]);   // 주심 두 명만 따로 넘긴다            sb.Append(official).Append(' ').Append(head).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 30 行
#include <algorithm>#include <iostream>#include <sstream>#include <string>#include <vector> // 심사 점수는 vector로 받는다. 값으로 받으면 복사본이라 마음대로 정렬해도 된다static long long score(int d, int k, std::vector<int> scores) {    std::sort(scores.begin(), scores.end());    long long sum = 0;    for (int i = k; i < static_cast<int>(scores.size()) - k; i++) sum += scores[i];    return d * sum;} int main() {    std::string line;    std::getline(std::cin, line);    int q = std::stoi(line);    for (int t = 0; t < q; t++) {        std::getline(std::cin, line);        std::istringstream in(line);        int d, k, x;        in >> d >> k;        std::vector<int> s;        while (in >> x) s.push_back(x);        long long official = score(d, k, s);        long long head = score(d, 0, {s[0], s[1]}); // 주심 두 명만 중괄호로 묶어 넘긴다        std::cout << official << ' ' << head << '\n';    }}
Cmain.c · 41 行
#include <stdio.h>#include <stdlib.h>#include <string.h> #define MAXM 100 static int by_value(const void *a, const void *b) {    return *(const int *)a - *(const int *)b;} /* C의 ...(stdarg.h)는 개수를 알 수 없고 배열을 펼쳐 넘길 수도 없다: 배열과 개수를 함께 받는다 */static long long score(int d, int k, const int *scores, int m) {    int ordered[MAXM];    memcpy(ordered, scores, (size_t)m * sizeof(int)); /* 부른 쪽 배열은 그대로 둔다 */    qsort(ordered, (size_t)m, sizeof(int), by_value);    long long sum = 0;    for (int i = k; i < m - k; i++) sum += ordered[i];    return d * sum;} int main(void) {    int q;    static char line[1024];    scanf("%d ", &q);    for (int t = 0; t < q; t++) {        if (!fgets(line, sizeof line, stdin)) break;        int d, k, used = 0, m = 0, s[MAXM];        char *p = line;        sscanf(p, "%d %d%n", &d, &k, &used);        p += used;        while (m < MAXM && sscanf(p, "%d%n", &s[m], &used) == 1) {            p += used;            m++;        }        long long official = score(d, k, s, m);        int heads[2] = {s[0], s[1]}; /* 주심 두 명만 따로 넘긴다 */        long long head = score(d, 0, heads, 2);        printf("%lld %lld\n", official, head);    }    return 0;}
Craykonmain.cray · 26 行
// 크레이콘에는 '몇 개든 받는 매개변수'가 없다 — 심사 점수를 목록 하나로 받는다점수(d, k, scores){    // 받은 목록은 부른 쪽 목록과 같은 것이다: 복사본을 정렬한다    ordered = scores.部分リスト(0, scores.個数);    ordered.並べ替え();    sum = 0;    繰り返す (i = k; i < ordered.個数 - k; i++)    {        sum += ordered[i];    }    返す d * sum;} q = コンソール.行読み().数に();繰り返す (t = 0; t < q; t++){    nums = コンソール.数読み();    d = nums[0];    k = nums[1];    s = nums.部分リスト(2, nums.個数 - 2);    official = 점수(d, k, s);    // 주심 두 명만 새 목록으로 묶어 넘긴다    head = 점수(d, 0, [s[0], s[1]]);    コンソール.書く(official + " " + head);}