AGC034 F - RNG and XOR

https://atcoder.jp/contests/agc034/tasks/agc034_f

Let a and b be arrays with 2^n elements. a*b denotes the xor convolution of a and b.

Let x=[x[0], x[1], ... , x[2^n-1]] be the answer and p=[p[0],...,p[2^n-1]] be the probability that i-th element is taken. The following relation holds.

\[ x \ast p = x + [2^{n}-1,-1,\ldots,-1]. \]

Let's consider the reason. The sum of x*p must be x[0]+...+x[2^n-1]. Thus, the first element of the right side must be 2^n-1.
H[x] denotes the hadamard transform of x. We then have

\[ H[x] \circ H[p] = H[x] + H[ [ 2^{n-1}-1,-1,\ldots,-1 ] ] \]

where a∘b denotes the bitwise product of arrays (also known as hadamard product.) Except i=0, we can figure out H[x][i]. For i=0, we cannot determine a value because H[p][0] = 1. Actually, we can assume that H[x][0] is any value. Once we determine H[x], we can obtain x by inverted hadamard transform. If H[x][0] is a wrong value, x[0],...,x[2^n-1] are also wrong. However, we can fix them because the answer is one of [x'[0], ... , x'[2^n-1]]=[x[0]+c, ... , x[2^n-1]+c]. We already know x'[0]=0, so c must be -x[0].

ABC127 F - Absolute Minima

https://atcoder.jp/contests/abc127/tasks/abc127_f

Maintain the first smallest half of a[i] and the second smallest half of a[i], call them L and R respectively. Then, the answer is sum(R)-sum(L) if L and R have the same number of elements.

To maintain them efficiently, we prepare two heaps, the one is a max-heap called L and the other is a min-heap called R. When given the input a[i] and b[i], we insert a[i] into both heaps, that is, do L.push(a[i]) and R.push(a[i]). After this operation, it might be L.top() > R.top(). If so, we swap them. After this, L.top() <= R.top() always holds. Note that L.top() <= R.top() implies L has the first smallest half of a[i] and R is also the same.

Since a[i] is counted doubly, the answer is a little different from the described above. It becomes (sum(R) - sum(L))/2. When L.top() > R.top(), two elements moves between L and R mutually. At this time, the (sum(R)-sum(L))/2 increases by x-y, where x and y are L.top() and R.top() respectively.

The following code is based on the explanation above. Clearly, we can use a balanced binary search tree or a binary indexed tree for solving this problem. BST and BIT appear in various situations. So it might be easier than the heap-based solution for experienced competitors.

By the way, as far as I know, two heap technique is written in "Cracking the Coding Interview." So it might be more well-known than many people think.

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>

using namespace std;

using ll = long long;
template<class T> using minheap = priority_queue<T, vector<T>, greater<T>>;
template<class T> using maxheap = priority_queue<T, vector<T>, less<T>>;

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int Q;
  cin >> Q;
  maxheap<ll> L;
  minheap<ll> R;
  ll ans = 0;
  while (Q--) {
    int type;
    cin >> type;
    if (type == 1) {
      ll a, b;
      cin >> a >> b;
      ans += b;
      L.push(a);
      R.push(a);
      if (L.top() > R.top()) {
        ll l = L.top(); L.pop();
        ll r = R.top(); R.pop();
        ans += l - r;
        L.push(r);
        R.push(l);
      }
    } else {
      cout << L.top() << ' ' << ans << '\n';
    }
  }
}

Codeforces #559 (Div. 1) A. The Party and Sweets

https://codeforces.com/contest/1158/problem/A

I didn't know the iterator has operator[] *1. I found this when I read his solution.

#include <vector>
#include <cassert>
using namespace std;
int main() {
  vector<int> a{1,2,3,4,5};
  assert(a.begin()[0] == 1);
  assert(a.begin()[1] == 2);
  assert(a.end()[-1] == 5);
  assert(a.end()[-2] == 4);
  assert(a.rbegin()[0] == 5);
  assert(a.rbegin()[1] == 4);
}

*1:According to http://www.cplusplus.com/reference/iterator/, only random access iterators have this operator. For example, if we need to find the second minimum of a set S, we cannot write S.begin()[1].

いろはちゃんコンテスト Day 1

I - リスのお仕事

Let us consider a graph whose vertices are (vertex ID, The cost used at last). If there exists a vertex having a lot of kinds of costs, it is difficult to update the distance efficiently. To perform efficiently, we prepare N special vertices (1,0),(2,0),...,(N,0) and connect (x,*) -> (x,0) with cost 1 and (x,0) -> (x,*) with cost 0. We can see that Dijkstra on this graph runs in O(N log^2 N), which is fast enough.

J - ヌクレオチド

When N is even, the inversion number is 2x(N/2-x) where x is the number of zeros in the first half. Look at two elements having different values. There are two cases. The first case is that 0 follows 1.

***0***1*** ***1***0***

In this case, the effect of two elements is exactly two. The second case is that 1 follows 0.

***1***0*** ***0***1***

Also in this case, the effect of two elements is exactly two. Thus, we can prove the first statement. We want to know the x such that 2x(N/2-x)=K. Since this is a quadratic equation, we can figure out the solutions by the quadratic formula. Once we get the x's, we just sum up C(N/2,x) for all x.

When N is odd, we can find out the answer similarly.

K - ルーレット

We do not have to compute the expectation but compute the sum of all possible patterns. It is not difficult to compute this.

L - をあ ぷろぶれむ

Fix the right end R, then the number of kinds of A[L] or ... or A[R] is at most 60. That is why, by or operation, the number of ones can increase at most 60 times. Let dp[R][X] be the number of intervals such that the right end is R and the bitwise OR of the elements is equal to X. We can compute this efficiently using std::map.

Codeforces Round #551 (Div. 2) F. Serval and Bonus Problem


https://codeforces.com/contest/1153/problem/F

Without loss of generality, we assume \(L=1\). The probability that x is covered by a single interval is \(2x(1-x)\). Let \(f(x)=2x(1-x)\), then the expectation of the length covered by exactly i intervals can be written by

\[ \int_{0}^{1} \binom{N}{i} f(x)^i (1-f(x))^{N-i} dx \]

If we have

\[ \int_{0}^{1} f(x)^i dx \]

the answer can be computed easily. The coefficients of \(f(x)^i\) can be computed by \(f(x)^{i-1}\) in O(N) time. The total time complexity is O(N^2).

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

const int MOD = 998244353;

struct mint {
    int n;
    mint(int n_ = 0) : n(n_) {}
};

mint operator+(mint a, mint b) { a.n += b.n; if (a.n >= MOD) a.n -= MOD; return a; }
mint operator-(mint a, mint b) { a.n -= b.n; if (a.n < 0) a.n += MOD; return a; }
mint operator*(mint a, mint b) { return (long long)a.n * b.n % MOD; }
mint &operator+=(mint &a, mint b) { return a = a + b; }
mint &operator-=(mint &a, mint b) { return a = a - b; }
mint &operator*=(mint &a, mint b) { return a = a * b; }

mint modpow(mint a, int b) {
  mint res = 1;
  while (b > 0) {
    if (b & 1) res *= a;
    a *= a;
    b >>= 1;
  }
  return res;
}

mint modinv(mint a) {
  return modpow(a, MOD - 2);
}

mint F[100001] = {1, 1};
mint R[100001] = {1, 1};
mint I[100001] = {0, 1};

mint C(int n, int r) {
  if (n < 0 || r < 0 || n < r) return 0;
  return F[n] * R[n - r] * R[r];
}

void init() {
  for (int i = 2; i <= 100000; i++) {
    I[i] = I[MOD % i] * (MOD - MOD / i);
    F[i] = F[i - 1] * i;
    R[i] = R[i - 1] * I[i];
  }
}

mint dp[2020][4040];
mint idp[2020];

int main() {
  init();
  int N, K, L;
  cin >> N >> K >> L;
  // P(x) = 2x(1-x) = -2x^2 + 2x
  dp[0][0] = 1;
  for (int i = 0; i < N; i++) {
    for (int j = 0; j <= 4000; j++) {
      dp[i + 1][j + 2] -= 2 * dp[i][j];
      dp[i + 1][j + 1] += 2 * dp[i][j];
    }
  }
  for (int i = 0; i <= N; i++) {
    for (int j = 0; j <= 4000; j++) {
      idp[i] += I[j + 1] * dp[i][j];
    }
  }
  mint ans = 0;
  for (int i = K; i <= N; i++) {
    // \int_0^1 C(N,i) * P(x)^i * (1-P(x))^{N-i}
    for (int j = 0; j <= N - i; j++) {
      if (j % 2 == 0) {
        ans += C(N,i) * C(N-i,j) * idp[i + j];
      } else {
        ans -= C(N,i) * C(N-i,j) * idp[i + j];
      }
    }
  }
  ans *= L;
  cout << ans.n << endl;
}