{ }codelper
尺取り法複数の戻り値P0069

整列された数で和が S になる二つ

一行目に n と S、二行目に小さい順に(同じ値があってもよい)整列された整数 n 個 a₁ … aₙ が与えられる。
aᵢ + aⱼ = S かつ i < j となる二つの位置 i, j を見つけて "i j" と出力せよ(位置は 1 から数える)。
同じ位置を二回使うことはできない。
答えが複数あれば i が最も小さいもの、その中で j が最も大きいものを出力する。
そのような二つの位置がなければ -1 を出力する。

入力
2 ≤ n ≤ 10,000、-2,000,000,000 ≤ aᵢ ≤ 2,000,000,000、-4,000,000,000 ≤ S ≤ 4,000,000,000、a₁ ≤ a₂ ≤ … ≤ aₙ
出力
"i j" の一行、または -1
例 1 · stdin
6 4
1 1 2 3 3 3
stdout
1 6
例 2 · stdin
3 10
1 5 8
stdout
-1
main.py
入力(stdin)

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

$ 準備完了

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

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

すべての組を試すと n = 10,000 のとき約 5 千万回で遅くなります。
整列されているので尺取り法(二つのポインタ)で両端から始め、和が小さければ左を、大きければ右を一つ動かすと n 回以内で終わります。
この方法は自然に、i が最小でその次に j が最大の答えを先に見つけます。
答えが二つ(i, j)なので、関数から二つの値を返す方法が言語ごとに違います:Python のタプル return i, j、JavaScript の配列 return [i, j] と const [i, j] = …、TypeScript はタプル型 [number, number]、C# のタプル (int, int) と var (i, j) = …、C++ std::pair と auto [i, j] = …、Java はタプルがないので int[](または record)、C はポインタ引数 int *pi、Craykon はリスト 返す [i, j];。
罠は二つ:lo <= hi で回すと一つの要素を二回使い、1 5 9 で 5 + 5 = 10 を見つけてしまいます。
また値が 20 億までなので二つの和は int(約 21 億)を超えることがあります — C・C++・Java・C# は long long/long で受け取る必要があります(Java・C# はあふれると負の数に回り込み、C・C++ では未定義動作なので合うことも間違うこともあります)。
Python・JavaScript・TypeScript・Craykon はそのままで大丈夫です。

Pythonmain.py · 18 行
def find_pair(a, s):    """a[i] + a[j] == s 인 (i, j)를 1부터 센 자리로 돌려준다. 없으면 (-1, -1)."""    lo, hi = 0, len(a) - 1    while lo < hi:        total = a[lo] + a[hi]        if total == s:            return lo + 1, hi + 1        if total < s:            lo += 1        else:            hi -= 1    return -1, -1  n, s = map(int, input().split())a = list(map(int, input().split()))i, j = find_pair(a, s)print(-1 if i == -1 else f"{i} {j}")
JavaScriptmain.js · 16 行
// a[i] + a[j] === s 인 [i, j]를 1부터 센 자리로 돌려준다. 없으면 [-1, -1].function findPair(a, s) {  let lo = 0;  let hi = a.length - 1;  while (lo < hi) {    const total = a[lo] + a[hi];    if (total === s) return [lo + 1, hi + 1];    if (total < s) lo++;    else hi--;  }  return [-1, -1];} const [n, s, ...a] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [i, j] = findPair(a, s);console.log(i === -1 ? "-1" : `${i} ${j}`);
TypeScriptmain.ts · 18 行
import { readFileSync } from "node:fs"; // a[i] + a[j] === s 인 [i, j]를 1부터 센 자리로 돌려준다. 없으면 [-1, -1].function findPair(a: number[], s: number): [number, number] {  let lo = 0;  let hi = a.length - 1;  while (lo < hi) {    const total = a[lo] + a[hi];    if (total === s) return [lo + 1, hi + 1];    if (total < s) lo++;    else hi--;  }  return [-1, -1];} const [n, s, ...a]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [i, j] = findPair(a, s);console.log(i === -1 ? "-1" : `${i} ${j}`);
JavaMain.java · 30 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    // a[i] + a[j] == s 인 {i, j}를 1부터 센 자리로 돌려준다. 없으면 {-1, -1}.    static int[] findPair(long[] a, long s) {        int lo = 0, hi = a.length - 1;        while (lo < hi) {            long total = a[lo] + a[hi];            if (total == s) return new int[] {lo + 1, hi + 1};            if (total < s) lo++;            else hi--;        }        return new int[] {-1, -1};    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int n = Integer.parseInt(st.nextToken());        long s = Long.parseLong(st.nextToken());        st = new StringTokenizer(in.readLine());        long[] a = new long[n];        for (int k = 0; k < n; k++) a[k] = Long.parseLong(st.nextToken());        int[] p = findPair(a, s);        System.out.println(p[0] == -1 ? "-1" : p[0] + " " + p[1]);    }}
C#Main.cs · 27 行
using System;using System.Linq; class Program{    // a[i] + a[j] == s 인 (i, j)를 1부터 센 자리로 돌려준다. 없으면 (-1, -1).    static (int, int) FindPair(long[] a, long s)    {        int lo = 0, hi = a.Length - 1;        while (lo < hi)        {            long total = a[lo] + a[hi];            if (total == s) return (lo + 1, hi + 1);            if (total < s) lo++;            else hi--;        }        return (-1, -1);    }     static void Main()    {        long s = long.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[1]);        long[] a = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray();        var (i, j) = FindPair(a, s);        Console.WriteLine(i == -1 ? "-1" : $"{i} {j}");    }}
C++main.cpp · 26 行
#include <iostream>#include <utility>#include <vector> // a[i] + a[j] == s 인 {i, j}를 1부터 센 자리로 돌려준다. 없으면 {-1, -1}.std::pair<int, int> findPair(const std::vector<long long>& a, long long s) {    int lo = 0, hi = static_cast<int>(a.size()) - 1;    while (lo < hi) {        long long total = a[lo] + a[hi];        if (total == s) return {lo + 1, hi + 1};        if (total < s) lo++;        else hi--;    }    return {-1, -1};} int main() {    int n;    long long s;    std::cin >> n >> s;    std::vector<long long> a(n);    for (auto& x : a) std::cin >> x;    auto [i, j] = findPair(a, s);    if (i == -1) std::cout << "-1\n";    else std::cout << i << " " << j << "\n";}
Cmain.c · 28 行
#include <stdio.h> /* 값 두 개는 포인터로 돌려준다. 찾으면 1, 없으면 0. */static int find_pair(const long long *a, int n, long long s, int *pi, int *pj) {    int lo = 0, hi = n - 1;    while (lo < hi) {        long long total = a[lo] + a[hi];        if (total == s) {            *pi = lo + 1;            *pj = hi + 1;            return 1;        }        if (total < s) lo++;        else hi--;    }    return 0;} int main(void) {    static long long a[10000];    int n, i, j;    long long s;    scanf("%d %lld", &n, &s);    for (int k = 0; k < n; k++) scanf("%lld", &a[k]);    if (find_pair(a, n, s, &i, &j)) printf("%d %d\n", i, j);    else puts("-1");    return 0;}
Craykonmain.cray · 36 行
// a[i] + a[j] == s 인 [i, j]를 1부터 센 자리로 돌려준다. 없으면 [-1, -1].짝찾기(a, s){    lo = 0;    hi = a.個数 - 1;    間 (lo < hi)    {        total = a[lo] + a[hi];        もし (total == s)        {            返す [lo + 1, hi + 1];        }        もし (total < s)        {            lo += 1;        }        でなければ        {            hi -= 1;        }    }    返す [-1, -1];} 첫줄 = コンソール.数読み();s = 첫줄[1];a = コンソール.数読み();답 = 짝찾기(a, s);もし (답[0] == -1){    コンソール.書く(-1);}でなければ{    コンソール.書く(답[0] + " " + 답[1]);}