AtCoder が提供しているABC(AtCoder Beginner Contest)276 のF問題をC++で解いてみました。ABC276は、2022年11月5日21:00に実施されました。
AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。
F問題 Double Chance(Difficulty : 1562)
問題はリンク先をご覧ください。
セグメント木を二つ使うことにより解くことができます。AtCoder Problems による Difficulty は、1562 でした。
解答案
この分子の式を展開すると、以下となります。
最初の項は、
右辺の最初の項は、
C++ プログラム例(ABC276F)
上で考察したようにセグメント木を2つ用意します。ACL を使いました。
- セグメント木 seg1 で、
より大きい、 の総和を求めます。 - セグメント木 seg2 で、
より小さい、 の個数を求めます。 - 998244353 との剰余を求めるためにセグメント木と同じく ACL を使いました。
ACL のおかげで全体がすっきりと書けています。以下が、C++プログラムとなります。
#include <bits/stdc++.h>
#include <atcoder/modint>
#include <atcoder/segtree>
using namespace std;
using namespace atcoder;
typedef long long int ll;
typedef modint998244353 mint;
ll op(ll a, ll b)
{
return a + b;
}
ll e()
{
return 0LL;
}
int main()
{
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
segtree<ll, op, e> seg1(200001);
segtree<ll, op, e> seg2(200001);
mint prev = (mint)0;
for (int i = 0; i < n; ++i) {
mint t = 0;
t += seg1.prod(a[i], 200001);
seg1.set(a[i], seg1.get(a[i]) + a[i]);
t += seg2.prod(0, a[i]) * a[i];
seg2.set(a[i], seg2.get(a[i]) + 1);
prev += 2 * t + (mint)a[i];
mint result = prev / (i + 1) / (i + 1);
cout << result.val() << endl;
}
return 0;
}
このプログラムは、AC(Accepted=正しいプログラム)と判定されました。
Python のセグメント木について
Python は、セグメント木を標準ライブラリとしては用意していません。このブログの Python プログラムは、なるべく言語標準のライブラリで実装したいと考えています。このような事情で、この記事では、Python への移植版のプログラムの紹介を省略します。
最後に
コンテスト中には解けませんでしたが、セグメント木を使うと解けました。理解を深めるために記事にしました。
引き続き ABC の問題を紹介していきます。