AtCoder Beginner Contest 023

Submission #985917

Source codeソースコード

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public class Main {
  void run() {
    int r = ni();
    int c = ni();
    int k = ni();
    int n = ni();
    int[] R = new int[r + 1];
    int[] C = new int[c + 1];
    int[] X = new int[n];
    int[] Y = new int[n];
    ArrayList<Pair<Integer, Pair<Integer, Integer>>> dot = new ArrayList<>();
    for (int i = 0; i < n; ++i) {
      int x = ni();
      int y = ni();
      R[x]++;
      C[y]++;
      X[i] = x;
      Y[i] = y;
    }
    for (int i = 0; i < n; ++i) {
      int x = X[i];
      int y = Y[i];
      dot.add(new Pair<>(y, new Pair<>(R[x], x)));
    }
    Collections.sort(dot);
    debug(dot);
    ArrayList<Pair<Integer, Integer>> list = new ArrayList<>();
    for (int i = 1; i <= r; ++i) {
      list.add(new Pair<>(R[i], i));
    }
    Collections.sort(list);
    long cnt = 0;
    for (int i = 1; i <= c; ++i) {
      // 被ってる
      int u = k - C[i] + 1;
      // 被っているドットの個数
      int num = (~Collections.binarySearch(dot, new Pair<>(i, new Pair<>(u + 1, -1))))
          - (~Collections.binarySearch(dot, new Pair<>(i, new Pair<>(u, -1))));
      cnt += num;
      // 間
      int t = k - C[i];
      if (t >= 0) {
        int left = ~Collections.binarySearch(list, new Pair<>(t, -1));
        int right = ~Collections.binarySearch(list, new Pair<>(t + 1, -1));
        int mum = (~Collections.binarySearch(dot, new Pair<>(i, new Pair<>(t + 1, -1))))
            - (~Collections.binarySearch(dot, new Pair<>(i, new Pair<>(t, -1))));
        cnt += right - left - mum;
      }
    }
    System.out.println(cnt);
  }

  Scanner sc = new Scanner(System.in);

  public static void main(String[] args) {
    new Main().run();
  }

  int ni() {
    return Integer.parseInt(sc.next());
  }

  void debug(Object... os) {
    System.err.println(Arrays.deepToString(os));
  }

  class BIT<T> {
    int n;
    ArrayList<T> bit;
    BiFunction<T, T, T> bif;

    /**
     * 1-indexed なBinary Indexed Treeを構築する
     *
     * @param n   容量
     * @param bif 適用させる関数
     * @param sup 初期値
     */
    BIT(int n, BiFunction<T, T, T> bif, Supplier<T> sup) {
      this.n = n;
      bit = new ArrayList<>(n + 1);
      for (int i = 0; i < n + 1; ++i) {
        bit.add(sup.get());
      }
      this.bif = bif;
    }

    /**
     * iの位置の値をvで更新する
     *
     * @param i index
     * @param v 新しい値
     */
    void set(int i, T v) {
      for (int x = i; x <= n; x += x & -x) {
        bit.set(x, bif.apply(bit.get(x), v));
      }
    }

    /**
     * クエリー
     *
     * @param defaultValue 初期値
     * @param i            index
     * @return [1, i]までfを適用した結果
     */
    T reduce(T defaultValue, int i) {
      T ret = defaultValue;
      for (int x = i; x > 0; x -= x & -x) {
        ret = bif.apply(ret, bit.get(x));
      }
      return ret;
    }
  }

  class SegmentTree<T> {
    int n;
    ArrayList<T> dat;
    BiFunction<T, T, T> bif;
    Supplier<T> sup;

    /**
     * 0-indexed なSegment Treeを構築する
     *
     * @param n_  要求容量
     * @param bif 適用させる関数
     * @param sup 初期値
     */
    SegmentTree(int n_, BiFunction<T, T, T> bif, Supplier<T> sup) {
      n = 1;
      while (n < n_) n *= 2;

      dat = new ArrayList<>(2 * n - 1);
      for (int i = 0; i < 2 * n - 1; ++i) {
        dat.add(sup.get());
      }
      this.bif = bif;
      this.sup = sup;
    }

    /**
     * kの位置の値をvで更新する
     *
     * @param k index
     * @param v 新しい値
     */
    void set(int k, T v) {
      k += n - 1;
      dat.set(k, v);
      while (k > 0) {
        k = (k - 1) / 2;
        dat.set(k, bif.apply(dat.get(k * 2 + 1), dat.get(k * 2 + 2)));
      }
    }

    /**
     * クエリー
     *
     * @param l はじめ
     * @param r おわり
     * @return [l, r)での演算bifを適用した結果を返す
     */
    T reduce(int l, int r) {
      return _reduce(l, r, 0, 0, n);
    }

    T _reduce(int a, int b, int k, int l, int r) {
      if (r <= a || b <= l) return sup.get();
      if (a <= l && r <= b) return dat.get(k);
      T vl = _reduce(a, b, k * 2 + 1, l, (l + r) / 2);
      T vr = _reduce(a, b, k * 2 + 2, (l + r) / 2, r);
      return bif.apply(vl, vr);
    }
  }

  class Pair<F extends Comparable<F>, S extends Comparable<S>> implements Comparable<Pair<F, S>> {
    F f;
    S s;

    Pair() {
    }

    Pair(F f, S s) {
      this.f = f;
      this.s = s;
    }

    Pair(Pair<F, S> p) {
      f = p.f;
      s = p.s;
    }

    @Override
    public int compareTo(Pair<F, S> p) {
      if (f.compareTo(p.f) != 0) {
        return f.compareTo(p.f);
      }
      return s.compareTo(p.s);
    }

    @Override
    public int hashCode() {
      return f.hashCode() ^ s.hashCode();
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || this.f == null || this.s == null) {
        return false;
      }
      if (this.getClass() != o.getClass()) {
        return false;
      }
      Pair p = (Pair) o;
      return this.f.equals(p.f) && this.s.equals(p.s);
    }

    @Override
    public String toString() {
      return "{" + f.toString() + ", " + s.toString() + "}";
    }
  }

  /**
   * ユークリッドの互除法
   *
   * @return a と b の最大公約数
   */
  long gcd(long a, long b) {
    if (b == 0) {
      return a;
    }
    return gcd(b, a % b);
  }

  /**
   * 拡張ユークリッドの互除法
   *
   * @return mx + ny = gcd(m, n)となるような(x, y)を返す
   */
  Pair<Long, Long> gcd_ex(long m, long n) {
    long[][] mat = _gcd_ex(m, n);
    return new Pair<>(mat[0][0], mat[0][1]);
  }

  long[][] _gcd_ex(long m, long n) {
    if (n == 0) {
      return new long[][]{{1, 0}, {0, 1}};
    }
    long k = m / n;
    long[][] K = new long[][]{{0, 1}, {1, -k}};
    long[][] r = _gcd_ex(n, m % n);
    long[][] dst = new long[2][2];
    for (int y = 0; y < 2; ++y)
      for (int x = 0; x < 2; ++x)
        for (int i = 0; i < 2; ++i)
          dst[y][x] += r[y][i] * K[i][x];
    return dst;
  }

  long MOD = 1_000_000_007;

  /**
   * 繰り返し2乗法を用いたべき乗の実装
   *
   * @return a^r (mod 1,000,000,007)
   */
  long pow(long a, long r) {
    long sum = 1;
    while (r > 0) {
      if ((r & 1) == 1) {
        sum *= a;
        sum %= MOD;
      }
      a *= a;
      a %= MOD;
      r >>= 1;
    }
    return sum;
  }

  /**
   * 組み合わせ
   * O(n)
   *
   * @return {}_nC_r
   */
  long C(int n, int r) {
    long sum = 1;
    for (int i = n; 0 < i; --i) {
      sum *= i;
      sum %= MOD;
    }
    long s = 1;
    for (int i = r; 0 < i; --i) {
      s *= i;
      s %= MOD;
    }
    sum *= pow(s, MOD - 2);
    sum %= MOD;

    long t = 1;
    for (int i = n - r; 0 < i; --i) {
      t *= i;
      t %= MOD;
    }
    sum *= pow(t, MOD - 2);
    sum %= MOD;

    return sum;
  }

  double GOLDEN_RATIO = (1.0 + Math.sqrt(5)) / 2.0;

  /**
   * 黄金分割探索
   *
   * @param left  下限
   * @param right 上限
   * @param f     探索する関数
   * @param comp  上に凸な関数を探索するときは、Comparator.comparingDouble(Double::doubleValue)
   *              下に凸な関数を探索するときは、Comparator.comparingDouble(Double::doubleValue).reversed()
   * @return 極値の座標x
   */
  double goldenSectionSearch(double left, double right, Function<Double, Double> f, Comparator<Double> comp) {
    double c1 = divideInternally(left, right, 1, GOLDEN_RATIO);
    double c2 = divideInternally(left, right, GOLDEN_RATIO, 1);
    double d1 = f.apply(c1);
    double d2 = f.apply(c2);
    while (right - left > 1e-9) {
      if (comp.compare(d1, d2) > 0) {
        right = c2;
        c2 = c1;
        d2 = d1;
        c1 = divideInternally(left, right, 1, GOLDEN_RATIO);
        d1 = f.apply(c1);
      } else {
        left = c1;
        c1 = c2;
        d1 = d2;
        c2 = divideInternally(left, right, GOLDEN_RATIO, 1);
        d2 = f.apply(c2);
      }
    }
    return right;
  }

  /**
   * [a,b]をm:nに内分する点を返す
   */
  double divideInternally(double a, double b, double m, double n) {
    return (n * a + m * b) / (m + n);
  }

  /**
   * http://alexbowe.com/popcount-permutations/
   * bitの立っている数が小さい順にループしたいときに使う。
   * ex)
   * <pre>
   * for (int i = 0; i < 25; ++i) {
   *   int bits = (1 << i) - 1;
   *   long m = C(25, num);
   *   for (j = 0; j < m; ++j) {
   *     ...(25個の中からi個bitが立っている)
   *     if (bits != 0)
   *       bits = next_perm(bits);
   *   }
   * }
   * </pre>
   *
   * @param v 現在のbit列
   * @return 次のbit列
   */
  int next_perm(int v) {
    int t = (v | (v - 1)) + 1;
    return t | ((((t & -t) / (v & -v)) >> 1) - 1);
  }

  /**
   * http://qiita.com/p_shiki37/items/65c18f88f4d24b2c528b
   */
  static class FastScanner {
    private final InputStream in;
    private final byte[] buffer = new byte[1024];
    private int ptr = 0;
    private int buflen = 0;

    public FastScanner(InputStream in) {
      this.in = in;
    }

    private boolean hasNextByte() {
      if (ptr < buflen) {
        return true;
      } else {
        ptr = 0;
        try {
          buflen = in.read(buffer);
        } catch (IOException e) {
          e.printStackTrace();
        }
        if (buflen <= 0) {
          return false;
        }
      }
      return true;
    }

    private int readByte() {
      if (hasNextByte()) return buffer[ptr++];
      else return -1;
    }

    private static boolean isPrintableChar(int c) {
      return 33 <= c && c <= 126;
    }

    private void skipUnprintable() {
      while (hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++;
    }

    public boolean hasNext() {
      skipUnprintable();
      return hasNextByte();
    }

    public String next() {
      if (!hasNext()) throw new NoSuchElementException();
      StringBuilder sb = new StringBuilder();
      int b = readByte();
      while (isPrintableChar(b)) {
        sb.appendCodePoint(b);
        b = readByte();
      }
      return sb.toString();
    }

    public long nextLong() {
      if (!hasNext()) throw new NoSuchElementException();
      long n = 0;
      boolean minus = false;
      int b = readByte();
      if (b == '-') {
        minus = true;
        b = readByte();
      }
      if (b < '0' || '9' < b) {
        throw new NumberFormatException();
      }
      while (true) {
        if ('0' <= b && b <= '9') {
          n *= 10;
          n += b - '0';
        } else if (b == -1 || !isPrintableChar(b)) {
          return minus ? -n : n;
        } else {
          throw new NumberFormatException();
        }
        b = readByte();
      }
    }
  }
}

Submission

Task問題 C - 収集王
User nameユーザ名 arukuka
Created time投稿日時
Language言語 Java8 (OpenJDK 1.8.0)
Status状態 AC
Score得点 100
Source lengthソースコード長 11507 Byte
File nameファイル名
Exec time実行時間 1549 ms
Memory usageメモリ使用量 122004 KB

Test case

Set

Set name Score得点 / Max score Cases
Sample - subtask0-sample01.txt,subtask0-sample02.txt,subtask0-sample03.txt
Subtask1 30 / 30 subtask0-sample01.txt,subtask0-sample02.txt,subtask0-sample03.txt,subtask1-01.txt,subtask1-02.txt,subtask1-03.txt,subtask1-04.txt,subtask1-05.txt,subtask1-06.txt,subtask1-07.txt,subtask1-08.txt,subtask1-09.txt,subtask1-10.txt,subtask1-11.txt,subtask1-12.txt,subtask1-13.txt,subtask1-14.txt,subtask1-15.txt
Subtask2 70 / 70 subtask0-sample01.txt,subtask0-sample02.txt,subtask0-sample03.txt,subtask1-01.txt,subtask1-02.txt,subtask1-03.txt,subtask1-04.txt,subtask1-05.txt,subtask1-06.txt,subtask1-07.txt,subtask1-08.txt,subtask1-09.txt,subtask1-10.txt,subtask1-11.txt,subtask1-12.txt,subtask1-13.txt,subtask1-14.txt,subtask1-15.txt,subtask2-01.txt,subtask2-02.txt,subtask2-03.txt,subtask2-04.txt,subtask2-05.txt,subtask2-06.txt,subtask2-07.txt,subtask2-08.txt,subtask2-09.txt,subtask2-10.txt,subtask2-11.txt,subtask2-12.txt,subtask2-13.txt,subtask2-14.txt,subtask2-15.txt

Test case

Case name Status状態 Exec time実行時間 Memory usageメモリ使用量
subtask0-sample01.txt AC 287 ms 28880 KB
subtask0-sample02.txt AC 283 ms 28884 KB
subtask0-sample03.txt AC 284 ms 28844 KB
subtask1-01.txt AC 282 ms 28916 KB
subtask1-02.txt AC 286 ms 29000 KB
subtask1-03.txt AC 302 ms 28956 KB
subtask1-04.txt AC 292 ms 28856 KB
subtask1-05.txt AC 286 ms 28944 KB
subtask1-06.txt AC 294 ms 28940 KB
subtask1-07.txt AC 285 ms 29060 KB
subtask1-08.txt AC 291 ms 29052 KB
subtask1-09.txt AC 288 ms 28960 KB
subtask1-10.txt AC 297 ms 29108 KB
subtask1-11.txt AC 299 ms 29016 KB
subtask1-12.txt AC 322 ms 29064 KB
subtask1-13.txt AC 288 ms 29092 KB
subtask1-14.txt AC 300 ms 29056 KB
subtask1-15.txt AC 296 ms 29028 KB
subtask2-01.txt AC 368 ms 33924 KB
subtask2-02.txt AC 382 ms 36140 KB
subtask2-03.txt AC 704 ms 57612 KB
subtask2-04.txt AC 1171 ms 111976 KB
subtask2-05.txt AC 1320 ms 111968 KB
subtask2-06.txt AC 1549 ms 120852 KB
subtask2-07.txt AC 1106 ms 88272 KB
subtask2-08.txt AC 1494 ms 121884 KB
subtask2-09.txt AC 1410 ms 119680 KB
subtask2-10.txt AC 1408 ms 119928 KB
subtask2-11.txt AC 1377 ms 119056 KB
subtask2-12.txt AC 1430 ms 119756 KB
subtask2-13.txt AC 1389 ms 122004 KB
subtask2-14.txt AC 1467 ms 113732 KB
subtask2-15.txt AC 1430 ms 117248 KB