{ }codelper
双指针P0260

合并两个入口的入场记录

音乐厅有 A 和 B 两个入口。
每个入口按进入的先后记录了观众的入场时刻(秒)。
所以两份记录各自从小的时刻起依次排列(可能有多个相同的时刻)。
把两份记录合并,按入场时刻的顺序做成一份名单。
时刻相同时,A 入口的观众排在 B 入口的观众前面。
同一入口的观众保持原记录中的顺序。
名单最前面是 1 号。
第一行按 A 记录的顺序输出 A 入口观众们的名单编号,用一个空格隔开。
第二行按 B 记录的顺序,用同样的方式输出 B 入口观众们的名单编号。
输入第一行给出 A 记录的数量 n 和 B 记录的数量 m,第二行给出 A 的 n 个时刻,第三行给出 B 的 m 个时刻。

输入
1 ≤ n, m ≤ 10,000,0 ≤ 时刻 ≤ 1,000,000,000(整数)。
每行的时刻按不减的顺序给出
输出
两行:A 观众们的名单编号,B 观众们的名单编号
样例 1 · stdin
4 3
5 9 9 120
3 9 40
stdout
2 3 4 7
1 5 6
main.py
输入(stdin)

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

$ 就绪

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

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

两份记录已经排好序,所以在每份记录上各放一根手指(位置 i、j),把较早的那位放进名单,只把那一边的手指移一格,n + m 步就结束。
时刻相同时 A 在前,所以选 A 的条件是 a[i] <= b[j]。
写成 < 的话,相同时刻 B 会先进去。
一份记录先用完时,另一份剩下的要全部接在后面。
只在 while (i < n && j < m) 时循环然后停下,就会漏掉尾巴,所以把条件写成 j == m || (i < n && a[i] <= b[j]),在一个循环里处理到底。
这时要先问 i < n,才不会读到已用完记录的范围外(&& 在前面为假时不看后面。
反过来写成 a[i] <= b[j] && i < n,Python、Java、C#、Craykon 会因越界错误停止)。
合在一起再排序也可以,但 JS/TS 的 sort() 没有比较函数时会转成字符串按字典序排,100 会排在 9 前面。
在 Java 中用 == 比较 List<Integer> 的两个值,比较的是是否同一个对象,所以 -128~127 以外的相同时刻会被判为不同。
放进 int[],或者用 equals、intValue()。
在一行中用空格连接输出数字时,Python print(*pos)、JS/TS/C# join(" ")、Craykon 控制台.输出(列表) 只在中间加空格,C、C++、Java 要自己注意不要在第一个数前面多出空格。

Pythonmain.py · 18 行
n, m = map(int, input().split())a = list(map(int, input().split()))b = list(map(int, input().split())) pos_a, pos_b = [], []i = j = 0place = 1while i < n or j < m:    # A를 고르는 때: B가 다 끝났거나, A의 시각이 B보다 이르거나 같을 때(같으면 A가 먼저)    if j == m or (i < n and a[i] <= b[j]):        pos_a.append(place)        i += 1    else:        pos_b.append(place)        j += 1    place += 1print(*pos_a)print(*pos_b)
JavaScriptmain.js · 17 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, m] = lines[0].trim().split(/\s+/).map(Number);const a = lines[1].trim().split(/\s+/).map(Number);const b = lines[2].trim().split(/\s+/).map(Number);const posA = [], posB = [];let i = 0, j = 0;for (let place = 1; place <= n + m; place++) {  // B가 끝났거나 A가 이르거나 같으면 A가 먼저  if (j === m || (i < n && a[i] <= b[j])) {    posA.push(place);    i++;  } else {    posB.push(place);    j++;  }}console.log(posA.join(" ") + "\n" + posB.join(" "));
TypeScriptmain.ts · 17 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, m] = lines[0].trim().split(/\s+/).map(Number);const a: number[] = lines[1].trim().split(/\s+/).map(Number);const b: number[] = lines[2].trim().split(/\s+/).map(Number);const posA: number[] = [], posB: number[] = [];let i = 0, j = 0;for (let place = 1; place <= n + m; place++) {  if (j === m || (i < n && a[i] <= b[j])) {    posA.push(place);    i++;  } else {    posB.push(place);    j++;  }}console.log(posA.join(" ") + "\n" + posB.join(" "));
JavaMain.java · 33 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    static int[] readInts(BufferedReader br, int k) throws Exception {        StringTokenizer st = new StringTokenizer(br.readLine());        int[] r = new int[k];        for (int t = 0; t < k; t++) r[t] = Integer.parseInt(st.nextToken());        return r;    }     public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(br.readLine());        int n = Integer.parseInt(st.nextToken()), m = Integer.parseInt(st.nextToken());        int[] a = readInts(br, n), b = readInts(br, m);   // int[]라 ==가 값을 비교한다        StringBuilder outA = new StringBuilder(), outB = new StringBuilder();        int i = 0, j = 0;        for (int place = 1; place <= n + m; place++) {            if (j == m || (i < n && a[i] <= b[j])) {                if (outA.length() > 0) outA.append(' ');                outA.append(place);                i++;            } else {                if (outB.length() > 0) outB.append(' ');                outB.append(place);                j++;            }        }        System.out.print(outA + "\n" + outB + "\n");    }}
C#Main.cs · 31 行
using System;using System.Collections.Generic; class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(first[0]), m = int.Parse(first[1]);        int[] a = Array.ConvertAll(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries), int.Parse);        int[] b = Array.ConvertAll(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries), int.Parse);        var posA = new List<int>(n);        var posB = new List<int>(m);        int i = 0, j = 0;        for (int place = 1; place <= n + m; place++)        {            if (j == m || (i < n && a[i] <= b[j]))            {                posA.Add(place);                i++;            }            else            {                posB.Add(place);                j++;            }        }        Console.WriteLine(string.Join(" ", posA));        Console.WriteLine(string.Join(" ", posB));    }}
C++main.cpp · 30 行
#include <iostream>#include <vector> void printLine(const std::vector<int>& p) {    for (size_t t = 0; t < p.size(); t++) std::cout << (t ? " " : "") << p[t];    std::cout << "\n";} int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int n, m;    std::cin >> n >> m;    std::vector<int> a(n), b(m);    for (int& x : a) std::cin >> x;    for (int& x : b) std::cin >> x;    std::vector<int> posA, posB;    int i = 0, j = 0;    for (int place = 1; place <= n + m; place++) {        if (j == m || (i < n && a[i] <= b[j])) {            posA.push_back(place);            i++;        } else {            posB.push_back(place);            j++;        }    }    printLine(posA);    printLine(posB);}
Cmain.c · 28 行
#include <stdio.h> static int a[10000], b[10000];static int pos_a[10000], pos_b[10000]; static void print_line(const int *p, int k) {    for (int t = 0; t < k; t++) printf(t ? " %d" : "%d", p[t]);    printf("\n");} int main(void) {    int n, m;    scanf("%d %d", &n, &m);    for (int t = 0; t < n; t++) scanf("%d", &a[t]);    for (int t = 0; t < m; t++) scanf("%d", &b[t]);    int i = 0, j = 0;    for (int place = 1; place <= n + m; place++) {        /* B가 끝났거나 A가 이르거나 같으면 A가 먼저 */        if (j == m || (i < n && a[i] <= b[j])) {            pos_a[i++] = place;        } else {            pos_b[j++] = place;        }    }    print_line(pos_a, n);    print_line(pos_b, m);    return 0;}
Craykonmain.cray · 27 行
first = 控制台.读数字();n = first[0];m = first[1];a = 控制台.读数字();b = 控制台.读数字();posA = [];posB = [];i = 0;j = 0;循环 (place = 1; place <= n + m; place++){    // B가 끝났거나, A가 남아 있고 A의 시각이 이르거나 같으면 A가 먼저    // &&는 앞이 거짓이면 뒤를 보지 않으니 i < n을 먼저 묻는다    takeA = j == m || i < n && a[i] <= b[j];    如果 (takeA)    {        posA.添加(place);        i++;    }    否则    {        posB.添加(place);        j++;    }}控制台.输出(posA);控制台.输出(posB);