2024-05-05 00:19阅读: 1125评论: 2推荐: 6

AtCoder Beginner Contest 352

A - AtCoder Line (abc352 A)

题目大意

给定x,y,z,问 z是否在x,y之间。

解题思路

如果x>y,则交换 x,y,然后判断是否有 xzy即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, x, y, z;
cin >> n >> x >> y >> z;
if (x > y)
swap(x, y);
if (x <= z && z <= y)
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


B - Typing (abc352 B)

题目大意

给定字符串s,tst的子序列。现就近匹配,找到 s的每个字符就近匹配到的 t中的每个下标。

解题思路

按照就近匹配原则,匹配一次子序列即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
string s, t;
cin >> s >> t;
auto pos = t.begin();
for (auto c : s) {
while (pos != t.end() && *pos != c) {
pos = next(pos);
}
cout << (pos - t.begin() + 1) << ' ';
pos = next(pos);
}
cout << '\n';
return 0;
}


C - Standing On The Shoulders (abc352 C)

题目大意

给定n个巨人,巨人有肩高ai和头高bi

现依次放置每个巨人,每个巨人放在上一个巨人的肩上。

问最高的巨人的头高有多高。

解题思路

枚举最后的巨人是哪个,那么其头高就是bi+jiaj

所有可能的情况取最大值即为答案。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> a(n), b(n);
for (int i = 0; i < n; i++)
cin >> a[i] >> b[i];
LL suma = accumulate(a.begin(), a.end(), 0LL);
LL ans = 0;
for (int i = 0; i < n; i++) {
ans = max(suma - a[i] + b[i], ans);
}
cout << ans << '\n';
return 0;
}


D - Permutation Subsequence (abc352 D)

题目大意

给定一个排列pi和一个数k

找出k个下标,最小化下标极差,使得对应的pi组成的集合是一个连续的 k个数的集合。

解题思路

pos[i]表示数 i在原排列的位置。枚举这连续的k个数,比如是i,i+1,i+2,...,i+k1,那此时的极差就是 maxiji+k1(pos[j])miniji+k1(pos[j])

对所有的i取最小值,就是答案。

按顺序枚举i,此时就是求一个长度为 kpos区间的最大值和最小值,即经典的滑动窗口问题,用单调维护即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
vector<int> pos(n);
for (int i = 0; i < n; i++) {
int x;
cin >> x;
--x;
pos[x] = i;
}
int ans = n + 1;
deque<int> minn, maxx;
for (int i = 0; i < n; i++) {
while (!minn.empty() && i - minn.front() >= k) {
minn.pop_front();
}
while (!maxx.empty() && i - maxx.front() >= k) {
maxx.pop_front();
}
while (!minn.empty() && pos[i] <= pos[minn.back()]) {
minn.pop_back();
}
while (!maxx.empty() && pos[i] >= pos[maxx.back()]) {
maxx.pop_back();
}
minn.push_back(i);
maxx.push_back(i);
if (i >= k - 1)
ans = min(ans, pos[maxx.front()] - pos[minn.front()]);
}
cout << ans << '\n';
return 0;
}


E - Clique Connect (abc352 E)

题目大意

给定一张无向图,初始无边。

现依次进行q次操作,每次操作给定 ki个点 xi,j和边权 ci,将这 ki个点俩俩 连边,边权为c

问最后图是否连通,若连通,问最小生成树的权值。

解题思路

用并查集维护连通性,对于每次操作,就依次合并相邻两点xi,j,xi,j+1即可。那么总的复杂度是O(ki)。考虑如何求最小生成树。

参考kruskal算法,直接从边权最小的开始连边,连边就xi,j,xi,j+1相连即可,如果它们未相连的话。这个过程可以在并查集合并时顺便做了。

因此时间复杂度就是O(ki)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
class dsu {
public:
vector<int> p;
vector<int> sz;
int n;
dsu(int _n) : n(_n) {
p.resize(n);
sz.resize(n);
iota(p.begin(), p.end(), 0);
fill(sz.begin(), sz.end(), 1);
}
inline int get(int x) { return (x == p[x] ? x : (p[x] = get(p[x]))); }
inline bool unite(int x, int y) {
x = get(x);
y = get(y);
if (x != y) {
p[x] = y;
sz[y] += sz[x];
return true;
}
return false;
}
};
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<pair<vector<int>, int>> a(m);
for (auto& [p, c] : a) {
int k;
cin >> k >> c;
p.resize(k);
for (auto& i : p) {
cin >> i;
--i;
}
}
vector<int> id(m);
iota(id.begin(), id.end(), 0);
sort(id.begin(), id.end(),
[&](int i, int j) { return a[i].second < a[j].second; });
dsu d(n);
LL ans = 0;
for (auto& i : id) {
auto& [p, c] = a[i];
for (auto j : p) {
if (d.unite(p[0], j)) {
ans += c;
}
}
}
if (d.sz[d.get(0)] != n) {
ans = -1;
}
cout << ans << '\n';
return 0;
}


F - Estimate Order (abc352 F)

题目大意

n个人,排名唯一,给定关于这些人的m条排名信息,问每个人的名次是否能唯一确定。

信息为i,j,ck,表示第i个人的名次 ri与第 j个人的名字 rj 的差rirj=ck

解题思路

考虑朴素做法怎么做。

n个人,每条信息就给两个人连边,然后就得到有若干个连通块。

对于每个连通块,如果我指定其中一个人的排名,那该连通块的其他人的排名都唯一确定了。

朴素的做法就是依次指定每个连通块中任意一个人的排名,然后求得该连通块其他人的排名,没有冲突的话,就继续指定下一个连通块的任意一个人的排名。如果存在合法的排名,则记录下来。最后看每个连通块合法的排名的个数是否是 1,是则唯一确定,否则不唯一。

朴素做法的时间复杂度O(n!) ,这里可以加点优化,比如只有一个点的我们不考虑,那么最多只有n2个连通块,则此时的复杂度就是 Ann2,有 5e8

考虑优化,在搜索时我们保留了每个数字用在了哪个连通块上,因此其状态数是一个阶乘,但事实上这个状态是冗余的——我们只需要知道用了哪些数字,而不需要这些数字用在了哪些连通块上。

考虑转移,对当前连通块,我们需要枚举一个没用过的数字,然后求该连通块每个人的排名,看看排名是否唯一。也就是说,我们需要的状态仅仅只是数字的是否使用,就可以做到转移,而不需要知道数字用在了哪里,由此状态数可以从阶乘级别降到指数级别。

然后,再记忆化搜索一下就解决了。

即设dp[s]表示当前使用的数字状态是s, 剩余连通块填剩余数字,是否存在可行解。转移就枚举该连通块的一个数字,然后BFS下得到整个连通块需要用到的数字nxt,没冲突的话,如果dp[s|nxt]可行,则说明当前连通块填该数字是合法的,记录一下。

最后看每个连通块的合法数字个数是否唯一,是则能唯一确定。

这个dp的设计方式其实就是朴素的记忆化搜索,跟递归形式的 数位 dp很类似。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<vector<array<int, 2>>> edge(n);
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
--a, --b;
edge[a].push_back({b, -c});
edge[b].push_back({a, c});
}
int up = (1 << n);
vector<int> used(n, 0);
vector<int> st;
auto bfs1 = [&](int st) {
queue<int> team;
team.push(st);
used[st] = 1;
while (!team.empty()) {
int u = team.front();
team.pop();
for (auto& [v, c] : edge[u]) {
if (!used[v]) {
used[v] = 1;
team.push(v);
}
}
}
};
for (int i = 0; i < n; ++i) {
if (used[i]) {
continue;
}
st.push_back(i);
bfs1(i);
}
vector<int> dp(up, -1);
vector<set<int>> candidate(st.size());
dp.back() = 1;
auto bfs2 = [&](int st, int sc) -> array<int, 2> {
int ret = 0;
queue<array<int, 2>> team;
vector<int> val(n, -1);
team.push({st, sc});
val[st] = sc;
ret |= (1 << sc);
int sz = 0;
while (!team.empty()) {
auto [u, c] = team.front();
team.pop();
sz++;
for (auto& [v, w] : edge[u]) {
int nc = c + w;
if (val[v] == -1) {
if (nc < 0 || nc >= n || (ret >> nc) & 1) {
return {false, 0};
}
ret |= (1 << nc);
val[v] = nc;
team.push({v, nc});
} else if (val[v] != nc) {
return {false, 0};
}
}
}
assert(sz == __builtin_popcount(ret));
return {true, ret};
};
auto dfs = [&](auto&& dfs, int state, int pos) -> int {
if (dp[state] != -1)
return dp[state];
bool ok = false;
int start = st[pos];
for (int i = 0; i < n; ++i) {
auto [valid, nxt] = bfs2(start, i);
if (valid && ((state & nxt) == 0) &&
dfs(dfs, state | nxt, pos + 1)) {
ok = true;
candidate[pos].insert(i);
}
}
return dp[state] = ok;
};
dfs(dfs, 0, 0);
vector<int> ans(n, -2);
auto bfs3 = [&](int st, int w) {
queue<array<int, 2>> team;
team.push({st, w});
ans[st] = w;
while (!team.empty()) {
auto [u, c] = team.front();
team.pop();
for (auto& [v, w] : edge[u]) {
int nc = c + w;
if (ans[v] == -2) {
ans[v] = nc;
team.push({v, nc});
}
}
}
};
for (int i = 0; i < st.size(); ++i) {
if (candidate[i].size() == 1) {
bfs3(st[i], *candidate[i].begin());
}
}
for (int i = 0; i < n; ++i) {
cout << ans[i] + 1 << " \n"[i == n - 1];
}
return 0;
}


G - Socks 3 (abc352 G)

题目大意

抽屉里有n个颜色的袜子,各有 ai只。

现每次从抽屉里等概率取一只袜子,不放回,直到取出两只颜色相同的袜子为止。

问取出的袜子的期望只数。

解题思路

假设恰好取出i只袜子后,有两只颜色相同的概率是 qi,那么期望次数即为 iqi。(这个式子比较经典,是一个后缀和的后缀和的展开式。)

假设取出i只或以上后,有两只颜色相同的概率是 pi,即 pi=jiqi,是个后缀和,则 qi=pipi+1。代替上述期望式子得 pi

pi+1表示需要取超过i只袜子才能有两只袜子颜色相同的概率,换句话说,它就是取i只袜子,没有两只颜色相同的概率(这才需要取i+1只或以上才能有两只袜子颜色相同,它不意味着第 i+1只能取到颜色相同)。

而取i只颜色各不相同的概率,可先枚举对应的 i种颜色,然后对应数量相乘总情况数。从生成函数的角度考虑,每种颜色的生成函数是 aix+1,则所有颜色的生成函数相乘 (a1x+1)(a2x+1)...(anx+1)的结果的 xi的系数就是上述的分子,分母(总情况数)就是 Ctotktot=ai

因此需要求出 (a1x+1)(a2x+1)...(anx+1)的结果,朴素的乘法需要进行O(n)次,每次用 ntt优化的话,总复杂度也得是 O(n2logn)

因为每次相乘,多项式的最高幂才 +1,可以考虑分治,假设f(l,r)=lir(aix+1),要求f(1,n),则先求 f(1,n2)f(n2+1,n),再两者相乘,就得到 f(1,n),而 f(1,n2)f(n2+1,n)就递归求解。这样每次相乘,多项式的最高幂就会翻倍,最多翻log次就得到结果,而不是之前的n次。即总的时间复杂度是 O(nlog2n)

代码是贴了touristntt板子和取模板子。

(感觉转换部分不能一眼看透,上面说的感觉不像是本质

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
template <typename T> T inverse(T a, T m) {
T u = 0, v = 1;
while (a != 0) {
T t = m / a;
m -= t * a;
swap(a, m);
u -= t * v;
swap(u, v);
}
assert(m == 1);
return u;
}
template <typename T> class Modular {
public:
using Type = typename decay<decltype(T::value)>::type;
constexpr Modular() : value() {}
template <typename U> Modular(const U& x) { value = normalize(x); }
template <typename U> static Type normalize(const U& x) {
Type v;
if (-mod() <= x && x < mod())
v = static_cast<Type>(x);
else
v = static_cast<Type>(x % mod());
if (v < 0)
v += mod();
return v;
}
const Type& operator()() const { return value; }
template <typename U> explicit operator U() const {
return static_cast<U>(value);
}
constexpr static Type mod() { return T::value; }
Modular& operator+=(const Modular& other) {
if ((value += other.value) >= mod())
value -= mod();
return *this;
}
Modular& operator-=(const Modular& other) {
if ((value -= other.value) < 0)
value += mod();
return *this;
}
template <typename U> Modular& operator+=(const U& other) {
return *this += Modular(other);
}
template <typename U> Modular& operator-=(const U& other) {
return *this -= Modular(other);
}
Modular& operator++() { return *this += 1; }
Modular& operator--() { return *this -= 1; }
Modular operator++(int) {
Modular result(*this);
*this += 1;
return result;
}
Modular operator--(int) {
Modular result(*this);
*this -= 1;
return result;
}
Modular operator-() const { return Modular(-value); }
template <typename U = T>
typename enable_if<is_same<typename Modular<U>::Type, int>::value,
Modular>::type&
operator*=(const Modular& rhs) {
#ifdef _WIN32
uint64_t x =
static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value);
uint32_t xh = static_cast<uint32_t>(x >> 32),
xl = static_cast<uint32_t>(x), d, m;
asm("divl %4; \n\t" : "=a"(d), "=d"(m) : "d"(xh), "a"(xl), "r"(mod()));
value = m;
#else
value = normalize(static_cast<int64_t>(value) *
static_cast<int64_t>(rhs.value));
#endif
return *this;
}
template <typename U = T>
typename enable_if<is_same<typename Modular<U>::Type, int64_t>::value,
Modular>::type&
operator*=(const Modular& rhs) {
int64_t q = static_cast<int64_t>(static_cast<long double>(value) *
rhs.value / mod());
value = normalize(value * rhs.value - q * mod());
return *this;
}
template <typename U = T>
typename enable_if<!is_integral<typename Modular<U>::Type>::value,
Modular>::type&
operator*=(const Modular& rhs) {
value = normalize(value * rhs.value);
return *this;
}
Modular& operator/=(const Modular& other) {
return *this *= Modular(inverse(other.value, mod()));
}
template <typename U>
friend bool operator==(const Modular<U>& lhs, const Modular<U>& rhs);
template <typename U>
friend bool operator<(const Modular<U>& lhs, const Modular<U>& rhs);
template <typename U>
friend std::istream& operator>>(std::istream& stream, Modular<U>& number);
private:
Type value;
};
template <typename T>
bool operator==(const Modular<T>& lhs, const Modular<T>& rhs) {
return lhs.value == rhs.value;
}
template <typename T, typename U>
bool operator==(const Modular<T>& lhs, U rhs) {
return lhs == Modular<T>(rhs);
}
template <typename T, typename U>
bool operator==(U lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) == rhs;
}
template <typename T>
bool operator!=(const Modular<T>& lhs, const Modular<T>& rhs) {
return !(lhs == rhs);
}
template <typename T, typename U>
bool operator!=(const Modular<T>& lhs, U rhs) {
return !(lhs == rhs);
}
template <typename T, typename U>
bool operator!=(U lhs, const Modular<T>& rhs) {
return !(lhs == rhs);
}
template <typename T>
bool operator<(const Modular<T>& lhs, const Modular<T>& rhs) {
return lhs.value < rhs.value;
}
template <typename T>
Modular<T> operator+(const Modular<T>& lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) += rhs;
}
template <typename T, typename U>
Modular<T> operator+(const Modular<T>& lhs, U rhs) {
return Modular<T>(lhs) += rhs;
}
template <typename T, typename U>
Modular<T> operator+(U lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) += rhs;
}
template <typename T>
Modular<T> operator-(const Modular<T>& lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) -= rhs;
}
template <typename T, typename U>
Modular<T> operator-(const Modular<T>& lhs, U rhs) {
return Modular<T>(lhs) -= rhs;
}
template <typename T, typename U>
Modular<T> operator-(U lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) -= rhs;
}
template <typename T>
Modular<T> operator*(const Modular<T>& lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) *= rhs;
}
template <typename T, typename U>
Modular<T> operator*(const Modular<T>& lhs, U rhs) {
return Modular<T>(lhs) *= rhs;
}
template <typename T, typename U>
Modular<T> operator*(U lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) *= rhs;
}
template <typename T>
Modular<T> operator/(const Modular<T>& lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> operator/(const Modular<T>& lhs, U rhs) {
return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> operator/(U lhs, const Modular<T>& rhs) {
return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> power(const Modular<T>& a, const U& b) {
assert(b >= 0);
Modular<T> x = a, res = 1;
U p = b;
while (p > 0) {
if (p & 1)
res *= x;
x *= x;
p >>= 1;
}
return res;
}
template <typename T> string to_string(const Modular<T>& number) {
return to_string(number());
}
template <typename T>
std::ostream& operator<<(std::ostream& stream, const Modular<T>& number) {
return stream << number();
}
template <typename T>
std::istream& operator>>(std::istream& stream, Modular<T>& number) {
typename common_type<typename Modular<T>::Type, int64_t>::type x;
stream >> x;
number.value = Modular<T>::normalize(x);
return stream;
}
constexpr int md = 998244353;
using Mint = Modular<std::integral_constant<decay<decltype(md)>::type, md>>;
template <typename T> class NTT {
public:
using Type = typename decay<decltype(T::value)>::type;
static Type md;
static Modular<T> root;
static int base;
static int max_base;
static vector<Modular<T>> roots;
static vector<int> rev;
static void clear() {
root = 0;
base = 0;
max_base = 0;
roots.clear();
rev.clear();
}
static void init() {
md = T::value;
assert(md >= 3 && md % 2 == 1);
auto tmp = md - 1;
max_base = 0;
while (tmp % 2 == 0) {
tmp /= 2;
max_base++;
}
root = 2;
while (power(root, (md - 1) >> 1) == 1) {
root++;
}
assert(power(root, md - 1) == 1);
root = power(root, (md - 1) >> max_base);
base = 1;
rev = {0, 1};
roots = {0, 1};
}
static void ensure_base(int nbase) {
if (md != T::value) {
clear();
}
if (roots.empty()) {
init();
}
if (nbase <= base) {
return;
}
assert(nbase <= max_base);
rev.resize(1 << nbase);
for (int i = 0; i < (1 << nbase); i++) {
rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
}
roots.resize(1 << nbase);
while (base < nbase) {
Modular<T> z = power(root, 1 << (max_base - 1 - base));
for (int i = 1 << (base - 1); i < (1 << base); i++) {
roots[i << 1] = roots[i];
roots[(i << 1) + 1] = roots[i] * z;
}
base++;
}
}
static void fft(vector<Modular<T>>& a) {
int n = (int)a.size();
assert((n & (n - 1)) == 0);
int zeros = __builtin_ctz(n);
ensure_base(zeros);
int shift = base - zeros;
for (int i = 0; i < n; i++) {
if (i < (rev[i] >> shift)) {
swap(a[i], a[rev[i] >> shift]);
}
}
for (int k = 1; k < n; k <<= 1) {
for (int i = 0; i < n; i += 2 * k) {
for (int j = 0; j < k; j++) {
Modular<T> x = a[i + j];
Modular<T> y = a[i + j + k] * roots[j + k];
a[i + j] = x + y;
a[i + j + k] = x - y;
}
}
}
}
static vector<Modular<T>> multiply(vector<Modular<T>> a,
vector<Modular<T>> b) {
if (a.empty() || b.empty()) {
return {};
}
int eq = (a == b);
int need = (int)a.size() + (int)b.size() - 1;
int nbase = 0;
while ((1 << nbase) < need)
nbase++;
ensure_base(nbase);
int sz = 1 << nbase;
a.resize(sz);
b.resize(sz);
fft(a);
if (eq)
b = a;
else
fft(b);
Modular<T> inv_sz = 1 / static_cast<Modular<T>>(sz);
for (int i = 0; i < sz; i++) {
a[i] *= b[i] * inv_sz;
}
reverse(a.begin() + 1, a.end());
fft(a);
a.resize(need);
return a;
}
};
template <typename T> typename NTT<T>::Type NTT<T>::md;
template <typename T> Modular<T> NTT<T>::root;
template <typename T> int NTT<T>::base;
template <typename T> int NTT<T>::max_base;
template <typename T> vector<Modular<T>> NTT<T>::roots;
template <typename T> vector<int> NTT<T>::rev;
template <typename T> vector<Modular<T>> inverse(const vector<Modular<T>>& a) {
assert(!a.empty());
int n = (int)a.size();
vector<Modular<T>> b = {1 / a[0]};
while ((int)b.size() < n) {
vector<Modular<T>> x(a.begin(),
a.begin() + min(a.size(), b.size() << 1));
x.resize(b.size() << 1);
b.resize(b.size() << 1);
vector<Modular<T>> c = b;
NTT<T>::fft(c);
NTT<T>::fft(x);
Modular<T> inv = 1 / static_cast<Modular<T>>((int)x.size());
for (int i = 0; i < (int)x.size(); i++) {
x[i] *= c[i] * inv;
}
reverse(x.begin() + 1, x.end());
NTT<T>::fft(x);
rotate(x.begin(), x.begin() + (x.size() >> 1), x.end());
fill(x.begin() + (x.size() >> 1), x.end(), 0);
NTT<T>::fft(x);
for (int i = 0; i < (int)x.size(); i++) {
x[i] *= c[i] * inv;
}
reverse(x.begin() + 1, x.end());
NTT<T>::fft(x);
for (int i = 0; i < ((int)x.size() >> 1); i++) {
b[i + ((int)x.size() >> 1)] = -x[i];
}
}
b.resize(n);
return b;
}
template <typename T> vector<Modular<T>> inverse_old(vector<Modular<T>> a) {
assert(!a.empty());
int n = (int)a.size();
if (n == 1) {
return {1 / a[0]};
}
int m = (n + 1) >> 1;
vector<Modular<T>> b =
inverse(vector<Modular<T>>(a.begin(), a.begin() + m));
int need = n << 1;
int nbase = 0;
while ((1 << nbase) < need) {
++nbase;
}
NTT<T>::ensure_base(nbase);
int size = 1 << nbase;
a.resize(size);
b.resize(size);
NTT<T>::fft(a);
NTT<T>::fft(b);
Modular<T> inv = 1 / static_cast<Modular<T>>(size);
for (int i = 0; i < size; ++i) {
a[i] = (2 - a[i] * b[i]) * b[i] * inv;
}
reverse(a.begin() + 1, a.end());
NTT<T>::fft(a);
a.resize(n);
return a;
}
template <typename T>
vector<Modular<T>> operator*(const vector<Modular<T>>& a,
const vector<Modular<T>>& b) {
if (a.empty() || b.empty()) {
return {};
}
if (min(a.size(), b.size()) < 150) {
vector<Modular<T>> c(a.size() + b.size() - 1, 0);
for (int i = 0; i < (int)a.size(); i++) {
for (int j = 0; j < (int)b.size(); j++) {
c[i + j] += a[i] * b[j];
}
}
return c;
}
return NTT<T>::multiply(a, b);
}
template <typename T>
vector<Modular<T>>& operator*=(vector<Modular<T>>& a,
const vector<Modular<T>>& b) {
return a = a * b;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> a(n);
for (auto& x : a)
cin >> x;
int tot = accumulate(a.begin(), a.end(), 0);
auto solve = [&](auto solve, int l, int r) -> vector<Mint> {
if (l + 1 == r)
return {1, a[l]};
int m = (l + r) >> 1;
return solve(solve, l, m) * solve(solve, m, r);
};
vector<Mint> poly = solve(solve, 0, n);
Mint deno = 1, ans = 0;
for (int i = 0; i <= n; i++) {
ans += poly[i] / deno;
deno *= tot - i;
deno /= i + 1;
}
cout << ans << '\n';
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/18173063

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(1125)  评论(2编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.