Submission #950111


Source Code Expand

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 n = ni();
    TreeSet<Integer> notExistInPset = new TreeSet<>();
    for (int i = 0; i < n; ++i) {
      notExistInPset.add(i);
    }
    int[] p = new int[n];
    int k = 0;
    int[] countWildCardUntilPrev = new int[n];
    for (int i = 0; i < n; ++i) {
      countWildCardUntilPrev[i] = k;
      p[i] = ni() - 1;
      if (p[i] < 0) {
        ++k;
      } else {
        notExistInPset.remove(p[i]);
      }
    }
    long sumOfNotExistInP = notExistInPset.parallelStream().mapToLong(Long::valueOf).reduce(0, (a, b) -> (a + b) % MOD);

    long[] factorial = new long[n + 1];
    factorial[0] = 1;
    for (int i = 1; i <= n; ++i) {
      factorial[i] = i * factorial[i - 1];
      factorial[i] %= MOD;
    }

    int[] countIfSjSmallerThanSi = new int[n];
    BIT<Integer> bit = new BIT<>(n, (a, b) -> a + b, () -> 0);
    for (int i = 0; i < n; ++i) {
      if (p[i] >= 0) {
        bit.update(p[i] + 1, 1);
        countIfSjSmallerThanSi[i] = bit.reduce(p[i], () -> 0);
      }
    }

    ArrayList<Integer> notExitstInPlist = new ArrayList<>(notExistInPset);
    Collections.sort(notExitstInPlist);

    long unko = 0;
    if (k > 1) {
      for (int si : notExitstInPlist) {
//        notExistInPset.remove(si);
//        int num = notExistInPset.headSet(si).size(); O(n)な無駄な計算。下と同じ
        int num = Collections.binarySearch(notExitstInPlist, si);
        unko += (num * factorial[k - 2]) % MOD;
        unko %= MOD;
//        notExistInPset.add(si);
      }
    }

    long[] LUT = new long[n];
    long last = 0;
    if (k > 0) {
      for (int i = 0; i < n; ++i) {
        if (p[i] < 0) {
          LUT[i] = last;
          continue;
        }
        int num = -Collections.binarySearch(notExitstInPlist, p[i]) - 1;
        num = notExitstInPlist.size() - num;
        LUT[i] += (num * factorial[k - 1]) % MOD;
        LUT[i] %= MOD;
        LUT[i] += last;
        LUT[i] %= MOD;
        last = LUT[i];
      }
    }

    long sum = 0;
    sum += factorial[k];
    for (int i = 0; i < n; ++i) {
      long sub = 0;
      if (p[i] >= 0) {
        sub += (p[i] * factorial[k]) % MOD;
        sub %= MOD;
        sub -= (countIfSjSmallerThanSi[i] * factorial[k]) % MOD;
        sub += MOD;
        sub %= MOD;
        if (k > 0) {
//          int num = notExistInPset.headSet(p[i]).size(); 遅い
          int num = -Collections.binarySearch(notExitstInPlist, p[i]) - 1;
          sub -= (((num * factorial[k - 1])%MOD) * countWildCardUntilPrev[i]) % MOD;
          sub += MOD;
          sub %= MOD;
        }
      } else {
        sub += (sumOfNotExistInP * factorial[k - 1]) % MOD;
        sub %= MOD;
//        for (int j = 0; j < i; ++j) { このループがだめ
//          if (p[j] < 0) continue;
////          int num = notExistInPset.tailSet(p[j]).size(); 遅い
//          int num = -Collections.binarySearch(notExitstInPlist, p[j]) - 1;
//          num = notExitstInPlist.size() - num;
//          sub -= num * factorial[k - 1];
//          sub += (Math.abs(sub / MOD) + 1) * MOD;
//          sub %= MOD;
//        }
        if (i > 0) {
          sub -= LUT[i - 1];
          sub += MOD;
          sub %= MOD;
        }
        if (k > 1) {
//        ArrayList<Integer> list = new ArrayList<>(notExistInPset);
//          for (int si : list) { ゲロ遅い
//            notExistInPset.remove(si);
//            int num = notExistInPset.headSet(si).size();
//            sub -= num * factorial[k - 2] * countWildCardUntilPrev[i];
//            sub += (Math.abs(sub / MOD) + 1) * MOD;
//            sub %= MOD;
//            notExistInPset.add(si);
//          }
          sub -= (unko * countWildCardUntilPrev[i]) % MOD;
          sub += MOD;
          sub %= MOD;
        }
      }
      sub *= factorial[n - 1 - i];
      sub %= MOD;
      sum += sub;
      sum %= MOD;
    }
    sum %= MOD;

    System.out.println(sum);
  }

  FastScanner sc = new FastScanner(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;

    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;
    }

    void update(int i, T v) {
      for (int x = i; x <= n; x += x & -x) {
        bit.set(x, bif.apply(bit.get(x), v));
      }
    }

    T reduce(int i, Supplier<T> sup) {
      T ret = sup.get();
      for (int x = i; x > 0; x -= x & -x) {
        ret = bif.apply(ret, bit.get(x));
      }
      return ret;
    }
  }

  long 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;
  }

  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);
  }

  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 Info

Submission Time
Task E - Encyclopedia of Permutations
User arukuka
Language Java8 (OpenJDK 1.8.0)
Score 1200
Code Size 9171 Byte
Status AC
Exec Time 1768 ms
Memory 108276 KB

Judge Result

Set Name Sample Subtask All
Score / Max Score 0 / 0 500 / 500 700 / 700
Status
AC × 5
AC × 33
AC × 58
Set Name Test Cases
Sample 0_000.txt, 0_001.txt, 0_002.txt, 0_003.txt, 0_004.txt
Subtask 0_000.txt, 0_001.txt, 0_002.txt, 0_003.txt, 0_004.txt, 1_005.txt, 1_006.txt, 1_007.txt, 1_008.txt, 1_009.txt, 1_010.txt, 1_011.txt, 1_012.txt, 1_013.txt, 1_014.txt, 1_015.txt, 1_016.txt, 1_017.txt, 1_018.txt, 1_019.txt, 1_020.txt, 1_021.txt, 1_022.txt, 1_023.txt, 1_024.txt, 1_025.txt, 1_026.txt, 1_027.txt, 1_028.txt, 1_029.txt, 1_030.txt, 1_031.txt, 1_032.txt
All 0_000.txt, 0_001.txt, 0_002.txt, 0_003.txt, 0_004.txt, 1_005.txt, 1_006.txt, 1_007.txt, 1_008.txt, 1_009.txt, 1_010.txt, 1_011.txt, 1_012.txt, 1_013.txt, 1_014.txt, 1_015.txt, 1_016.txt, 1_017.txt, 1_018.txt, 1_019.txt, 1_020.txt, 1_021.txt, 1_022.txt, 1_023.txt, 1_024.txt, 1_025.txt, 1_026.txt, 1_027.txt, 1_028.txt, 1_029.txt, 1_030.txt, 1_031.txt, 1_032.txt, 2_033.txt, 2_034.txt, 2_035.txt, 2_036.txt, 2_037.txt, 2_038.txt, 2_039.txt, 2_040.txt, 2_041.txt, 2_042.txt, 2_043.txt, 2_044.txt, 2_045.txt, 2_046.txt, 2_047.txt, 2_048.txt, 2_049.txt, 2_050.txt, 2_051.txt, 2_052.txt, 2_053.txt, 2_054.txt, 2_055.txt, 2_056.txt, 2_057.txt
Case Name Status Exec Time Memory
0_000.txt AC 242 ms 15172 KB
0_001.txt AC 231 ms 14288 KB
0_002.txt AC 201 ms 14032 KB
0_003.txt AC 236 ms 14540 KB
0_004.txt AC 209 ms 14664 KB
1_005.txt AC 226 ms 14412 KB
1_006.txt AC 206 ms 14152 KB
1_007.txt AC 230 ms 14416 KB
1_008.txt AC 262 ms 15664 KB
1_009.txt AC 221 ms 14672 KB
1_010.txt AC 243 ms 15172 KB
1_011.txt AC 238 ms 14912 KB
1_012.txt AC 279 ms 15828 KB
1_013.txt AC 233 ms 15316 KB
1_014.txt AC 257 ms 15688 KB
1_015.txt AC 235 ms 14788 KB
1_016.txt AC 247 ms 15160 KB
1_017.txt AC 194 ms 14540 KB
1_018.txt AC 299 ms 15292 KB
1_019.txt AC 259 ms 14800 KB
1_020.txt AC 252 ms 15700 KB
1_021.txt AC 242 ms 15176 KB
1_022.txt AC 254 ms 15416 KB
1_023.txt AC 256 ms 15032 KB
1_024.txt AC 275 ms 15824 KB
1_025.txt AC 202 ms 14288 KB
1_026.txt AC 267 ms 15312 KB
1_027.txt AC 238 ms 14672 KB
1_028.txt AC 235 ms 15184 KB
1_029.txt AC 266 ms 15292 KB
1_030.txt AC 252 ms 15168 KB
1_031.txt AC 285 ms 15304 KB
1_032.txt AC 250 ms 15296 KB
2_033.txt AC 1137 ms 81488 KB
2_034.txt AC 633 ms 66484 KB
2_035.txt AC 1323 ms 85576 KB
2_036.txt AC 951 ms 78276 KB
2_037.txt AC 1416 ms 96512 KB
2_038.txt AC 1031 ms 82448 KB
2_039.txt AC 1503 ms 96980 KB
2_040.txt AC 788 ms 66684 KB
2_041.txt AC 1585 ms 96532 KB
2_042.txt AC 554 ms 33760 KB
2_043.txt AC 1631 ms 97160 KB
2_044.txt AC 973 ms 73412 KB
2_045.txt AC 1690 ms 103640 KB
2_046.txt AC 1622 ms 93192 KB
2_047.txt AC 1724 ms 98880 KB
2_048.txt AC 799 ms 64064 KB
2_049.txt AC 1768 ms 99156 KB
2_050.txt AC 1011 ms 76720 KB
2_051.txt AC 1422 ms 98120 KB
2_052.txt AC 1022 ms 108276 KB
2_053.txt AC 1122 ms 81732 KB
2_054.txt AC 1502 ms 98448 KB
2_055.txt AC 1200 ms 99344 KB
2_056.txt AC 1182 ms 96024 KB
2_057.txt AC 1317 ms 95748 KB