結果
| 問題 | No.3767 Earth Mover's Distance Sum |
| コンテスト | |
| ユーザー |
aPNJ777
|
| 提出日時 | 2026-10-17 00:52:11 |
| 言語 | C++23 (gcc 15.3.0 + boost 1.92.0 + ACL) |
| 結果 |
AC
不安定
|
| 実行時間 | 215 ms / 2,000 ms |
| + 726µs | |
| コード長 | 15,877 bytes |
| 記録 | |
| コンパイル時間 | 2,980 ms |
| コンパイル使用メモリ | 346,340 KB |
| 実行使用メモリ | 30,748 KB |
| 最終ジャッジ日時 | 2026-10-17 00:52:25 |
| 合計ジャッジ時間 | 10,271 ms |
|
ジャッジサーバーID (参考情報) |
judge4_0 / judge2_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 29 |
ソースコード
//////////////////////////////////////// template start /////////////////////////////////////////
// https://atcoder.jp/contests/abc479/submissions/80038224 2026-10-14 19:59:22
#include <bits/stdc++.h>
using namespace std;
//using ll = long long;
using ld = long double;
using u32 = uint32_t;
using u64 = uint64_t;
using i128 = __int128_t;
using u128 = __uint128_t;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using vvvvvc = vector<vvvvc<T>>;
#define vv(type, name, h, w) vector<vector<type>> name(h, vector<type>(w))
#define vvv(type, name, h, w, l) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(l)))
#define vvvv(type, name, a, b, c, d) vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(d))))
#define vvvvv(type, name, a, b, c, d, e) vector<vector<vector<vector<vector<type>>>>> name(a, vector<vector<vector<vector<type>>>>(b, vector<vector<vector<type>>>(c, vector<vector<type>>(d, vector<type>(e)))))
#define elif else if
#define FOR1(a) for (long long _ = 0; _ < (long long)(a); _++)
#define FOR2(i, n) for (long long i = 0; i < (long long)(n); i++)
#define FOR3(i, l, r) for (long long i = l; i < (long long)(r); i++)
#define FOR4(i, l, r, c) for (long long i = l; i < (long long)(r); i += c)
#define FOR1_R(a) for (long long _ = (long long)(a) - 1; _ >= 0; _--)
#define FOR2_R(i, n) for (long long i = (long long)(n) - 1; i >= (long long)(0); i--)
#define FOR3_R(i, l, r) for (long long i = (long long)(r) - 1; i >= (long long)(l); i--)
#define FOR4_R(i, l, r, c) for (long long i = (long long)(r) - 1; i >= (long long)(l); i -= (c))
#define overload4(a, b, c, d, e, ...) e
#define FOR(...) overload4(__VA_ARGS__, FOR4, FOR3, FOR2, FOR1)(__VA_ARGS__)
#define FOR_R(...) overload4(__VA_ARGS__, FOR4_R, FOR3_R, FOR2_R, FOR1_R)(__VA_ARGS__)
#define FOR_in(a, A) for (auto a: A)
#define FOR_each(a, A) for (auto &&a: A)
#define FOR_subset(t, s) for(long long t = (s); t >= 0; t = (t == 0 ? -1 : (t - 1) & (s)))
#define all(x) x.begin(), x.end()
#define len(x) int(x.size())
int popcount(int x) { return __builtin_popcount(x); }
int popcount(uint32_t x) { return __builtin_popcount(x); }
int popcount(long long x) { return __builtin_popcountll(x); }
int popcount(uint64_t x) { return __builtin_popcountll(x); }
// __builtin_clz(x)は最上位bitからいくつ0があるか.
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(uint32_t x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(long long x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int topbit(uint64_t x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
// 入力
void rd() {}
void rd(char &c) { cin >> c; }
void rd(string &s) { cin >> s; }
void rd(int &x) { cin >> x; }
void rd(uint32_t &x) { cin >> x; }
void rd(long long &x) { cin >> x; }
void rd(uint64_t &x) { cin >> x; }
template<class T>
void rd(vector<T> &v) { for (auto& x:v) rd(x); }
void read() {}
template <class H, class... T>
void read(H &h, T &... t) { rd(h), read(t...); }
#define CHAR(...) \
char __VA_ARGS__; \
read(__VA_ARGS__)
#define STRING(...) \
string __VA_ARGS__; \
read(__VA_ARGS__)
#define INT(...) \
int __VA_ARGS__; \
read(__VA_ARGS__)
#define U32(...) \
uint32_t __VA_ARGS__; \
read(__VA_ARGS__)
#define LL(...) \
long long __VA_ARGS__; \
read(__VA_ARGS__)
#define U64(...) \
uint64_t __VA_ARGS__; \
read(__VA_ARGS__)
#define VC(t, a, n) \
vector<t> a(n); \
read(a)
#define VVC(t, a, h, w) \
vector<vector<t>> a(h, vector<t>(w)); \
read(a)
//出力
void wt() {}
void wt(const char c) { cout << c; }
void wt(const string s) { cout << s; }
void wt(int x) { cout << x; }
void wt(uint32_t x) { cout << x; }
void wt(long long x) { cout << x; }
void wt(uint64_t x) { cout << x; }
void wt(double x) { cout << fixed << setprecision(16) << x; }
void wt(long double x) { cout << fixed << setprecision(16) << x; }
template<class T>
void wt(const vector<T> v) {
int n = v.size();
for (int i = 0; i < n; i++) {
if (i) wt(' ');
wt(v[i]);
}
}
void print() { wt('\n'); }
template <class Head, class... Tail>
void print(Head &&head, Tail &&... tail) {
wt(head);
if (sizeof...(Tail)) wt(' ');
print(forward<Tail>(tail)...);
}
template <class T>
int bisect_left(const vector<T> & A, T x) {
auto idx = lower_bound(A.begin(), A.end(), x) - A.begin();
return idx;
}
template <class T>
int bisect_right(const vector<T> & A, T x) {
auto idx = upper_bound(A.begin(), A.end(), x) - A.begin();
return idx;
}
template <class T>
T min(vector<T> A) {
assert (A.size());
T S = A[0];
for (T a : A) S = min(a, S);
return S;
}
template <class T>
T max(vector<T> A) {
assert (A.size());
T S = A[0];
for (T a : A) S = max(a, S);
return S;
}
template <class T>
T add(T x, T y) { return x + y; }
template <class T>
bool chmin(T & x, T a) { return a < x ? (x = a, true) : false; }
template <class T>
bool chmax(T & x, T a) { return a > x ? (x = a, true) : false; }
template <class T>
T sum(vector<T> A) {
T S = 0;
for (int i = 0; i < int(A.size()); i++) S += A[i];
return S;
}
uint64_t random_u64(uint64_t l, uint64_t r) {
static std::random_device rd;
static std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dist(l, r);
return dist(gen);
}
long long floor_div(long long a, long long b) {
if (b < 0) a *= -1, b *= -1;
if (a >= 0) return a / b;
return -((-a + b - 1) / b);
}
long long ceil_div(long long a, long long b) {
if (b < 0) a *= -1, b *= -1;
if (a >= 0) return (a + b - 1) / b;
return - ((-a) / b);
}
long long gcd(long long a, long long b) {
while (a) {
b %= a;
if (b == 0) return a;
a %= b;
}
return b;
}
long long lcm(long long a, long long b) {
if (a * b == 0) return 0;
return a * b / gcd(a, b);
}
long long pow_mod(long long a, long long r, long long mod) {
long long res = 1, p = a % mod;
while (r) {
if ((r % 2) == 1) res = res * p % mod;
p = p * p % mod, r >>= 1;
}
return res;
}
long long mod_inv(long long a, long long mod) {
if (mod == 1) return 0;
a %= mod;
long long b = mod, s = 1, t = 0;
while (1) {
if (a == 1) return s;
t -= (b / a) * s;
b %= a;
if (b == 1) return t + mod;
s -= (a / b) * t;
a %= b;
}
}
pair<long long, long long> extgcd(long long a, long long b) {
long long s = a, t = b;
long long xs = 1, ys = 0, xt = 0, yt = 1;
while (t > 0) {
long long u = s / t;
s -= t * u;
xs -= xt * u;
ys -= yt * u;
swap(s, t);
swap(xs, xt), swap(ys, yt);
}
return {xs, ys};
}
pair<long long, long long> garner(vector<long long> Rem, vector<long long> Mod) {
assert (Rem.size() == Mod.size());
int n = int(Mod.size());
// garner
long long x = 0, prod = 1;
for (int i = 0; i < n; i++) {
if (Mod[i] == 1) continue;
long long g = gcd(prod, Mod[i]);
long long c = (Rem[i] + (Mod[i] - x % Mod[i])) % Mod[i];
if (c % g) return {-1, -1}; // not exist
long long m = Mod[i] / g;
c = (c / g) * mod_inv((prod / g) % m, m) % m;
x = x + c * prod;
prod *= m;
x %= prod;
}
return {x, prod};
}
long long garner2(vector<long long> Rem, vector<long long> Mod, long long mod) {
assert (Rem.size() == Mod.size());
int n = int(Mod.size());
// garner
vector<long long> C(n);
for (int i = 0; i < n; i++) {
long long x = 0, prod = 1;
for (int j = 0; j < i; j++) {
x = (x + C[j] * prod % Mod[i]) % Mod[i];
prod = (prod * Mod[j]) % Mod[i];
}
long long g = gcd(prod, Mod[i]);
long long c = (Rem[i] + (Mod[i] - x)) % Mod[i];
if (c % g) return -1; // not exist
long long m = Mod[i] / g;
c = (c / g) * mod_inv((prod / g) % m, m) % m;
Mod[i] /= g, C[i] = c;
}
long long ans = 0, c = 0;
for (int i = n - 1; i >= 0; i--) ans = ((ans * Mod[i]) % mod + C[i]) % mod, c = max(c, C[i]);
// 中華風
if (c == 0) {
ans = 1;
for (int i = 0; i < n; i++) ans = (ans * Mod[i]) % mod;
}
return ans;
}
long long Tonelli_Shanks(long long a, long long mod) {
a %= mod;
if (a < 2) return a;
if (pow_mod(a, (mod - 1) / 2, mod) != 1) return -1;
if (mod % 4 == 3) return pow_mod(a, (mod + 1) / 4, mod);
long long b = 3;
if (mod != 998244353) {
while (pow_mod(b, (mod - 1) / 2, mod) == 1) b = random_u64(2, mod - 1);
}
long long q = mod - 1;
long long Q = 0;
while (q % 2 == 0) Q++, q /= 2;
long long x = pow_mod(a, (q + 1) / 2, mod);
b = pow_mod(b, q, mod);
long long shift = 2;
while ((x * x) % mod != a) {
long long error = (((pow_mod(a, mod - 2, mod) * x) % mod) * x) % mod;
if (pow_mod(error, 1 << (Q - shift), mod) != 1) x = (x * b) % mod;
b = (b * b) % mod;
shift++;
}
return x;
}
//////////////////////////////////////// template end ////////////////////////////////////////
//////////////////////////////////////// modint start ////////////////////////////////////////
template <int mod>
struct modint {
static constexpr uint32_t umod = uint32_t(mod);
static_assert(umod < (uint32_t(1) << 31));
uint32_t val;
static modint raw(uint32_t v) {
modint x;
x.val = v % umod;
return x;
}
constexpr modint() : val(0) {}
constexpr modint(uint32_t x) : val(x % umod) {}
constexpr modint(uint64_t x) : val(x % umod) {}
constexpr modint(__uint128_t x) : val(x % umod) {}
constexpr modint(int x) : val((x %= int(umod)) < 0 ? x + umod : x) {};
constexpr modint(long long x) : val((x %= int(umod)) < 0 ? x + umod : x) {};
constexpr modint(__int128_t x) : val((x %= int(umod)) < 0 ? x + umod : x) {};
bool operator<(const modint &other) const { return val < other.val; }
modint &operator+=(const modint &p) {
if ((val += p.val) >= umod) val -= umod;
return *this;
}
modint &operator-=(const modint &p) {
if ((val += umod - p.val) >= umod) val -= umod;
return *this;
}
modint &operator*=(const modint &p) {
val = uint64_t(val) * p.val % umod;
return *this;
}
modint &operator/=(const modint &p) {
val = uint64_t(val) * p.inverse().val % umod;
return *this;
}
modint operator-() const { return modint::raw(val ? umod - val : uint32_t(0)); }
modint operator+(const modint &p) const { return modint(*this) += p; }
modint operator-(const modint &p) const { return modint(*this) -= p; }
modint operator*(const modint &p) const { return modint(*this) *= p; }
modint operator/(const modint &p) const { return modint(*this) /= p; }
bool operator==(const modint &p) const { return val == p.val; }
bool operator!=(const modint &p) const { return val != p.val; }
modint inverse() const {
int a = val, b = umod, s = 1, t = 0;
while (1) {
if (a == 1) return modint(s);
t -= (b / a) * s;
b %= a;
if (b == 1) return modint(t + umod);
s -= (a / b) * t;
a %= b;
}
}
modint pow(long long n) const {
if (n == 0) return modint(1);
if (val == 0) return modint(0);
n %= (long long)(umod - 1);
if (n < 0) n += umod - 1;
modint res(1), a(val);
while (n > 0) {
if (n & 1) res *= a;
a *= a;
n >>= 1;
}
return res;
}
uint32_t get() const { return val; }
static constexpr int get_mod() { return mod; }
static constexpr pair<int, int> ntt_info() {
if (mod == 167772161) return {25, 17};
if (mod == 469762049) return {26, 30};
if (mod == 754974721) return {24, 362};
if (mod == 880803841) return {23, 211};
if (mod == 998244353) return {23, 31};
return {-1, -1};
}
};
template <int mod>
void rd(modint<mod> &x) {
uint32_t y;
cin >> y;
x = y;
}
template <int mod>
void wt(modint<mod> x) { wt(x.val); }
template <class mint>
mint inverse(long long n) {
static bool prepared = 0;
static int N = 3000000, mod = mint::get_mod();
if (N > mod - 1) N = mod - 1;
static vector<mint> res(N + 1, mint(1));
if (prepared == 0) {
prepared = 1;
for (int i = 2; i <= N; i++) res[i] = -res[mod % i] * mint(mod / i);
}
if (n < 0) return mint(0);
if (n == 0) return mint(1); /////////////////
assert (n <= N);
return res[n];
}
template <typename mint>
mint fact(long long n) {
static bool prepared = 0;
static int N = 3000000, mod = mint::get_mod();
if (N > mod - 1) N = mod - 1;
static vector<mint> res(N + 1, mint(1));
if (prepared == 0) {
prepared = 1;
for (int i = 2; i <= N; i++) res[i] = res[i - 1] * mint(i);
}
if (n < 0) return mint(0);
assert (n <= N);
return res[n];
}
template <typename mint>
mint fact_inv(long long n) {
static bool prepared = 0;
static int N = 3000000, mod = mint::get_mod();
if (N > mod - 1) N = mod - 1;
static vector<mint> res(N + 1, mint(1));
if (prepared == 0) {
prepared = 1;
res[N] = fact<mint>(N).inverse();
for (int i = N - 1; i >= 1; i--) res[i] = res[i + 1] * mint(i + 1);
}
if (n < 0) return mint(0);
assert (n <= N);
return res[n];
}
template <typename mint>
mint binom(long long n, long long r) {
if (n < 0 || r < 0 || n < r) return 0;
mint res = fact<mint>(n) * (fact_inv<mint>(n - r) * fact_inv<mint>(r));
return res;
}
//////////////////////////////////////// modint end ////////////////////////////////////////
using mint = modint<998244353>;
/*
検索するとき
https://www.google.com/search?udm=14&q=
-ai
難読化???
todo ABCまでに github に code
*/
/*
貪欲にやればいい.
B_1 を決める.
A_1 が B_1 に (1, 2) で操作
A は B_1, A_1 + A_2 - B_1, ...
A_2 を B_2 に
B_1, B_2, A_1 + A_2 + A_3 - (B_1 + B_2)
操作回数は \sum (|A_1 + ... + A_i - (B_1 + ... + B_i)|)
|(A_1 + ... + A_i) - (B_1 + ... + B_i)| の寄与を求めればいい.
i 毎 a_i = A_1 + ... + A_i
a の寄与 B_i までの和 a以下のとき-, a以上+
fps
1/(1-x)^i の [x^a] まで と 1/(1-x)^{N-i} の積の [x^S]
i が 1 増える 左辺の変化, -binom(i+a,a) x^{a+1} を引いて, (1-x)で割る.
a が増える 左辺の変化 binom(i - 1 + a, i)x^a 足す.
ix /(1-x)^{i+1} の [x^a] まで と 1/(1-x)^{N-i} の積の [x^S]
i が増える. 左辺の変化, -ibinom(i-1+a,a) x^{a+1} を引いて, x /(1-x)^i の [x^a] まで足して, (1-x)で割る
*/
void solve() {
INT(N);
VC(int, A, N);
for (int i = 0; i < N - 1; i++) A[i + 1] += A[i];
int S = A.back();
mint ans = mint(0);
// b - a としたときの答え
for (int i = 1; i < N; i++) {
int a = A[i - 1];
mint res = mint(i) * binom<mint>(N + S - 1, S - 1) - mint(a) * binom<mint>(N - 1 + S, S);
ans += res;
}
// + a の寄与
int b = 0;
mint res = binom<mint>(N - 1 + S, S);
for (int i = 1; i < N; i++) {
int a = A[i - 1];
// i が増える.
res -= binom<mint>(i - 1 + b, b) * binom<mint>(N - i + (S - (b + 1)), S - (b + 1));
// b 増える
while (b < a) {
b++;
res += binom<mint>(i - 1 + b, b) * binom<mint>(N - i - 1 + S - b , S - b);
}
ans += mint(2 * a) * res;
}
// b の余分な寄与
b = 1, res = binom<mint>(N - 1 + S - 1, S - 1);
mint res1 = mint(0);
for (int i = 1; i < N; i++) {
int a = A[i - 1];
res1 -= mint(i - 1) * binom<mint>(i + b - 1, b - 1) * binom<mint>(N - i + (S - (b + 1)), S - (b + 1));
res -= binom<mint>(i + b - 1, b - 1) * binom<mint>(N - i + (S - (b + 1)), S - (b + 1));
res1 += res;
while (b < a) {
b++;
res += binom<mint>(i + b - 1, b - 1) * binom<mint>(N - i - 1 + S - b , S - b);
res1 += mint(i) * binom<mint>(i + b - 1, b - 1) * binom<mint>(N - i - 1 + S - b , S - b);
}
if (a >= 1) ans -= mint(2) * res1;
}
print(ans);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int testcases = 1;
//cin >> testcases;
FOR(testcases) solve();
}
aPNJ777