Solution Set【2024.1.20】
A. 整除
首先特殊考虑
对于
因此我们不妨考虑
发现在模
进而我们有:
因此我们可以将
不难发现通过这样的操作可以使得
否则我们以
因此在
综上,我们可以得出满足
至此我们得到了一个判定算法:枚举所有的正整数
下面我们尝试分析其复杂度,不难发现对于 std::map
维护
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::map<valueType, valueType> ValueMap;
typedef std::set<valueType> ValueSet;
typedef std::map<valueType, ValueSet> SetMap;
void solve() {
valueType N, M;
std::cin >> N >> M;
ValueMap A;
SetMap bucket;
valueType count = 0;
valueType sum = 0;
for (valueType i = 0; i < N; ++i) {
valueType c, a;
std::cin >> c >> a;
sum += c;
A[a % M] -= c;
A[(a + 1) % M] += c;
}
if (sum % M == 0)
++count;
{
auto iter = A.begin();
while (iter != A.end()) {
if (iter->second == 0)
iter = A.erase(iter);
else
++iter;
}
}
if (A.empty()) {
std::cout << -1 << '\n';
return;
}
for (auto const &[i, a] : A)
bucket[static_cast<valueType>(a)].insert(static_cast<valueType>(i));
std::function<bool(valueType)> Check = [&](valueType x) -> bool {
ValueMap rollBack;
auto Dec = [&](valueType i, valueType y) {// dec A[i] by y
bucket[A[i]].erase(i);
A[i] -= y;
bucket[A[i]].insert(i);
rollBack[i] += y;
};
auto Inc = [&](valueType i, valueType y) {// inc A[i] by y
bucket[A[i]].erase(i);
A[i] += y;
bucket[A[i]].insert(i);
rollBack[i] -= y;
};
while (bucket.begin()->second.empty())
bucket.erase(bucket.begin());
while (bucket.rbegin()->second.empty())
bucket.erase(std::prev(bucket.end()));
while (bucket.begin()->first <= -x || bucket.rbegin()->first >= x) {
while (bucket.begin()->first <= -x) {
ValueSet const S = bucket.begin()->second;
for (auto const &i : S) {
while (A[i] >= x) {
Dec(i, x);
Inc((i + 1) % M, 1);
}
while (A[i] <= -x) {
Inc(i, x);
Dec((i + 1) % M, 1);
}
}
while (bucket.begin()->second.empty())
bucket.erase(bucket.begin());
}
while (bucket.rbegin()->first >= x) {
ValueSet const S = bucket.rbegin()->second;
for (auto const &i : S) {
while (A[i] >= x) {
Dec(i, x);
Inc((i + 1) % M, 1);
}
while (A[i] <= -x) {
Inc(i, x);
Dec((i + 1) % M, 1);
}
}
while (bucket.rbegin()->second.empty())
bucket.erase(std::prev(bucket.end()));
}
while (bucket.begin()->second.empty())
bucket.erase(bucket.begin());
while (bucket.rbegin()->second.empty())
bucket.erase(std::prev(bucket.end()));
}
bool const result = bucket.size() == 1 && (bucket.begin()->first == 0 || bucket.begin()->first == x - 1 || bucket.begin()->first == -x + 1);
for (auto const &[i, y] : rollBack) {
bucket[A[i]].erase(i);
A[i] += y;
bucket[A[i]].insert(i);
}
return result;
};
valueType max = 0;
for (auto &[a, c] : A)
max = std::max(max, std::abs(c) + 1);
for (valueType i = 2; i <= max; ++i) {
if (Check(i))
++count;
}
std::cout << count << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
#ifndef LOCAL_STDIO
freopen("div.in", "r", stdin);
freopen("div.out", "w", stdout);
#endif
valueType T;
std::cin >> T;
for (valueType testcase = 0; testcase < T; ++testcase)
solve();
std::cout << std::flush;
return 0;
}
B. 词典
考虑对词典建出字典树,发现合法的词典对应的字典树一定满足:
- 存在
个叶子节点,分别对应 个单词。 - 对于父边权值为
的节点,其最多有一条权值为 的出边。
不难发现满足上述条件的字典树一定是唯一的,对应的词典也一定是合法的。因此我们只需要考虑在满足上述条件的字典树的最小代价即可。
设
其中
可以发现
不难发现
首先我们可以通过上述算法求出
时间复杂度为
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
valueType W(valueType n) {// 单次查询复杂度为 O(log n)
static constexpr valueType const B = 63;
valueType ans = 0;
for (valueType i = 0; i < B; ++i) {
if (n >= (1ll << (i + 1))) {
ans += (1ll << i) * (i + 1);
} else {
ans += (n - (1ll << i) + 1) * (i + 1);
break;
}
}
return ans;
}
constexpr valueType PreN = 1e5;
ValueVector PreF(PreN + 1);
constexpr double const Rate = 1.3, FindRange = 0.35;// 倍增倍率,查询范围,要求 Rate * (1 - FindRange) <= 1
constexpr valueType MaxDiff = 7000;// 差分数组最大值
constexpr valueType MaxN = 1e15; // 最大查询范围
std::array<std::pair<valueType, valueType>, MaxDiff> Diff;// 差分数组,first:最大的 m 使得 f_m - f_{m - 1} = i,second: f_m
valueType DiffSize = 0, PreDiff = 0;
void Pre() {// 预处理,复杂度为 O(PreN log PreN)
ValueVector G(PreN + 1, 0);
PreF[0] = 0;
G[0] = 0;
PreF[1] = W(1);
G[1] = W(1);
for (valueType i = 2; i <= PreN; ++i) {
PreF[i] = std::numeric_limits<valueType>::max();
valueType l = 1, r = i - 1, point = 1;
while (l <= r) {
valueType mid = (l + r) / 2;
if ((G[mid + 1] - G[mid]) + (PreF[i - (mid + 1)] - PreF[(i - mid)]) >= 0) {
point = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
PreF[i] = std::min(PreF[i], G[point] + PreF[i - point]);
PreF[i] += W(i);
G[i] = PreF[i] + W(i);
}
for (valueType i = 1; i <= PreN; ++i) {
valueType diff = PreF[i] - PreF[i - 1];
Diff[diff].first = i;
Diff[diff].second = PreF[i];
DiffSize = std::max(DiffSize, diff);
}
Diff[DiffSize].first = 0;
Diff[DiffSize].second = 0;
--DiffSize;
PreDiff = DiffSize;
}
valueType F_Extened(valueType n) {
if (n <= PreN)
return PreF[n];
valueType l = PreDiff, r = DiffSize, point = -1;
while (l <= r) {
valueType mid = (l + r) / 2;
if (Diff[mid].first <= n) {
point = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
if (!(point != -1 && (Diff[point + 1].first >= n || Diff[point].first == n))) {
std::cerr << "Error: " << n << '\n';
}
assert(point != -1 && (Diff[point + 1].first >= n || Diff[point].first == n));
return Diff[point].second + (n - Diff[point].first) * (point + 1);
}
valueType F_Solve(valueType n) {
auto Calc = [&](valueType x) -> valueType {
return W(n) + F_Extened(x) + W(x) + F_Extened(n - x);
};
valueType l = n * FindRange, r = n / 2, point = -1;
while (l <= r) {
valueType mid = (l + r) / 2;
if (Calc(mid + 1) >= Calc(mid)) {
point = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
// if (!(point != -1 && (Calc(point + 1) >= Calc(point) && Calc(point - 1) >= Calc(point)))) {
// throw std::runtime_error("Error");
// }
assert(point != -1 && (Calc(point + 1) >= Calc(point) && Calc(point - 1) >= Calc(point)));
return Calc(point);
}
void MainExtend() {
Pre();
valueType max = PreN, nowDiff = PreDiff + 1;
while (max < MaxN * Rate + 100) {
valueType const PreMax = max;
max = max * Rate;
valueType l = PreMax, r = max, point = PreMax;
while (l <= r) {
valueType const mid = (l + r) / 2;
if (F_Solve(mid) - F_Solve(mid - 1) <= nowDiff) {
point = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
Diff[nowDiff].first = point;
Diff[nowDiff].second = F_Solve(point);
max = point;
++nowDiff;
DiffSize = std::max(DiffSize, nowDiff - 1);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
#ifndef LOCAL_STDIO
freopen("dictionary.in", "r", stdin);
freopen("dictionary.out", "w", stdout);
#endif
MainExtend();
valueType T;
std::cin >> T;
for (valueType testcase = 0; testcase < T; ++testcase) {
valueType N;
std::cin >> N;
std::cout << F_Extened(N) << '\n';
}
std::cout << std::flush;
return 0;
}
C. 蒲公英
考虑上图的情况,
那么我们可以将边
进而可证明更改后的标号方案仍然合法。
发现若
我们考虑找到一个节点
首先可以发现为了满足儿子节点可以完成下放,那么儿子节点的标号一定是
可以发现,为了使得叶子节点可以一直传递下去,我们需要保证任意两次的操作中心尽可能的相近,因此可以发现一种操作方法:
因此在执行操作的过程中,除了第一次操作
下面考虑如何将被删除的子树添加回图中,设经过操作后的菊花图大小为
复杂度为
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::deque<valueType> ValueDeque;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::deque<ValuePair> PairDeque;
void dfs(valueType x, valueType from, ValueMatrix const &G, ValueVector &depth, valueType &D) {
if (depth[x] > depth[D])
D = x;
for (auto const &iter : G[x]) {
if (iter == from)
continue;
depth[iter] = depth[x] + 1;
dfs(iter, x, G, depth, D);
}
}
bool get(valueType x, valueType from, ValueMatrix const &G, valueType goal, ValueVector &path) {
if (x == goal) {
path.emplace_back(x);
return true;
}
for (auto const &iter : G[x]) {
if (iter == from)
continue;
if (get(iter, x, G, goal, path)) {
path.emplace_back(x);
return true;
}
}
return false;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
#ifndef LOCAL_STDIO
freopen("dandelion.in", "r", stdin);
freopen("dandelion.out", "w", stdout);
#endif
valueType N;
std::cin >> N;
if (N == 1) {
std::cout << "Yes\n";
std::cout << 1 << std::endl;
return 0;
}
if (N == 2) {
std::cout << "Yes\n";
std::cout << 1 << ' ' << 2 << std::endl;
return 0;
}
ValueMatrix G(N + 1);
for (valueType i = 1; i < N; ++i) {
valueType u, v;
std::cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
valueType Root;
{
valueType A = 0, B = 0, L = 0;
ValueVector depth(N + 1, 0);
dfs(1, 0, G, depth, A);
std::fill(depth.begin(), depth.end(), 0);
dfs(A, 0, G, depth, B);
L = depth[B] + 1;
ValueVector path;
get(A, -1, G, B, path);
Root = path[L / 2];
}
ValueVector ID(N + 1, 0);
std::sort(G[Root].begin(), G[Root].end(), [&](valueType a, valueType b) {
if ((G[a].size() & 1) != (G[b].size() & 1))
return (G[a].size() & 1) < (G[b].size() & 1); // G[x].size() - 1 -> 子树节点数量 (不含自己) (连向根的边代替自己计数)
else
return G[a].size() > G[b].size();
});
valueType Removed = -1, M = N;
if ((G[Root].size() & 1) == 0) {
Removed = G[Root].back();
G[Root].erase(std::find(G[Root].begin(), G[Root].end(), Removed));
G[Removed].erase(std::find(G[Removed].begin(), G[Removed].end(), Root));
M -= G[Removed].size() + 1;
}
ID[Root] = M;
ValueVector next(N + 1);
{
valueType x = M;
for (valueType i = M - 1; i >= 1; --i) {
if (x > M / 2) {
next[x] = x - i;
x = x - i;
} else {
next[x] = x + i;
x = x + i;
}
}
}
valueType id = M;
ValueDeque LeftPool, RightPool;
for (valueType i = (G[Root].size() + 1) / 2 + 1; i <= (M + 1) / 2; ++i)
LeftPool.emplace_back(i);
for (valueType i = M - (G[Root].size() + 1) / 2; i > (M + 1) / 2; --i)
RightPool.emplace_back(i);
for (auto const &y : G[Root]) {
id = next[id];
ID[y] = id;
valueType const sum = id + next[id];
auto Dist = [&](valueType x) {
return std::abs(2 * x - sum);
};
G[y].erase(std::find(G[y].begin(), G[y].end(), Root));
ValueVector set;
valueType const need = G[y].size();
set.reserve(need);
if (need == 0)
continue;
if (need == (LeftPool.size() + RightPool.size())) {
for (auto const &iter : LeftPool)
set.emplace_back(iter);
for (auto const &iter : RightPool)
set.emplace_back(iter);
LeftPool.clear();
RightPool.clear();
for (valueType i = 0; i < need; ++i)
ID[G[y][i]] = set[i];
continue;
}
while (LeftPool.size() >= 2 && Dist(LeftPool[LeftPool.size() - 1]) == Dist(LeftPool[LeftPool.size() - 2])) {
RightPool.emplace_back(LeftPool.back());
LeftPool.pop_back();
}
while (RightPool.size() >= 2 && Dist(RightPool[RightPool.size() - 1]) == Dist(RightPool[RightPool.size() - 2])) {
LeftPool.emplace_back(RightPool.back());
RightPool.pop_back();
}
if (LeftPool.empty() || RightPool.empty() || LeftPool.front() + RightPool.front() != sum) {
if (LeftPool.empty()) {
set.emplace_back(RightPool.front());
RightPool.pop_front();
} else if (RightPool.empty()) {
set.emplace_back(LeftPool.front());
LeftPool.pop_front();
} else if (Dist(LeftPool.front()) > Dist(RightPool.front())) {
set.emplace_back(LeftPool.front());
LeftPool.pop_front();
} else {
assert(Dist(LeftPool.front()) < Dist(RightPool.front()));
set.emplace_back(RightPool.front());
RightPool.pop_front();
}
}
if ((set.size() & 1) != (need & 1)) {
assert(Dist(LeftPool.back()) != Dist(RightPool.back()));
if (Dist(LeftPool.back()) < Dist(RightPool.back())) {
set.emplace_back(LeftPool.back());
LeftPool.pop_back();
} else {
assert(Dist(LeftPool.back()) > Dist(RightPool.back()));
set.emplace_back(RightPool.back());
RightPool.pop_back();
}
}
assert((set.size() & 1) == (need & 1));
while (set.size() < need) {
set.emplace_back(LeftPool.front());
LeftPool.pop_front();
set.emplace_back(RightPool.front());
RightPool.pop_front();
}
for (valueType i = 0; i < need; ++i)
ID[G[y][i]] = set[i];
}
if (Removed != -1) {
for (auto &id : ID)
if (id != 0)
++id;
ID[Removed] = 1;
valueType count = M + 1;
for (auto const &y : G[Removed])
ID[y] = ++count;
}
std::cout << "Yes\n";
for (valueType i = 1; i <= N; ++i)
std::cout << ID[i] << ' ';
std::cout << std::endl;
return 0;
}
[JSOI2011] 分特产
发现若不考虑每个同学都必须至少分得一个特产的限制,那么方案数可以直接计算,考虑到这个限制,我们可以使用二项式反演来计算答案。
设
根据二项式反演,我们有:
考虑如何计算
其中
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
namespace MODINT_WITH_FIXED_MOD {
constexpr valueType MOD = 1e9 + 7;
template<typename T1, typename T2>
void Inc(T1 &a, T2 b) {
a = a + b;
if (a >= MOD)
a -= MOD;
}
template<typename T1, typename T2>
void Dec(T1 &a, T2 b) {
a = a - b;
if (a < 0)
a += MOD;
}
template<typename T1, typename T2>
T1 sum(T1 a, T2 b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
template<typename T1, typename T2>
T1 sub(T1 a, T2 b) {
return a - b < 0 ? a - b + MOD : a - b;
}
template<typename T1, typename T2>
T1 mul(T1 a, T2 b) {
return (long long) a * b % MOD;
}
template<typename T1, typename T2>
void Mul(T1 &a, T2 b) {
a = (long long) a * b % MOD;
}
template<typename T1, typename T2>
T1 pow(T1 a, T2 b) {
T1 result = 1;
while (b > 0) {
if (b & 1)
Mul(result, a);
Mul(a, a);
b = b >> 1;
}
return result;
}
}// namespace MODINT_WITH_FIXED_MOD
using namespace MODINT_WITH_FIXED_MOD;
class BinomialCoefficient {
private:
valueType N;
ValueVector Fact, InvFact;
public:
BinomialCoefficient() = default;
BinomialCoefficient(valueType n) : N(n), Fact(N + 1, 1), InvFact(N + 1, 1) {
for (valueType i = 1; i <= N; ++i)
Fact[i] = mul(Fact[i - 1], i);
InvFact[N] = pow(Fact[N], MOD - 2);
for (valueType i = N - 1; i >= 0; --i)
InvFact[i] = mul(InvFact[i + 1], i + 1);
}
valueType operator()(valueType n, valueType m) {
if (n < 0 || m < 0 || n < m)
return 0;
if (m > N)
throw std::out_of_range("BinomialCoefficient::operator() : m > N");
if (n <= N)
return mul(Fact[n], mul(InvFact[m], InvFact[n - m]));
valueType result = 1;
for (valueType i = 0; i < m; ++i)
Mul(result, n - i);
Mul(result, InvFact[m]);
return result;
}
};
constexpr valueType V = 2005;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
BinomialCoefficient C(V);
ValueVector F(N + 1, 1), count(M, 0);
for (auto &x : count)
std::cin >> x;
for (valueType i = 0; i <= N; ++i) {
for (auto const &x : count)
Mul(F[i], C(x + (N - i) - 1, (N - i) - 1));
}
valueType ans = 0;
for (valueType i = 0; i <= N; ++i) {
if (i & 1)
Dec(ans, mul(F[i], C(N, i)));
else
Inc(ans, mul(F[i], C(N, i)));
}
std::cout << ans << std::endl;
return 0;
}
ABC219G Propagation
考虑根号分治,出边集合大小超过
复杂度为
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<bool> bitset;
typedef std::pair<valueType, valueType> ValuePair;
constexpr valueType B = 600;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M, Q;
std::cin >> N >> M >> Q;
ValueMatrix G(N + 1), T(N + 1);
ValueVector LastTime(N + 1, -1), Color(Q + 1, -1);
ValueVector Time(N + 1, -1);
ValueVector A(N + 1);
std::iota(A.begin(), A.end(), 0);
for (valueType i = 0; i < M; ++i) {
valueType u, v;
std::cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
bitset IsLargeDegree(N + 1);
for (valueType i = 1; i <= N; ++i) {
if (G[i].size() > B) {
IsLargeDegree[i] = true;
for (auto const &to : G[i])
T[to].push_back(i);
} else {
IsLargeDegree[i] = false;
}
}
for (valueType q = 1; q <= Q; ++q) {
valueType x;
std::cin >> x;
valueType last = Time[x];
for (auto const &from : T[x])
last = std::max(last, LastTime[from]);
if (last != Time[x]) {
A[x] = Color[last];
Time[x] = last;
}
LastTime[x] = q;
Time[x] = q;
Color[q] = A[x];
if (!IsLargeDegree[x]) {
for (auto const &to : G[x]) {
A[to] = A[x];
Time[to] = q;
}
}
}
for (valueType x = 1; x <= N; ++x) {
valueType last = Time[x];
for (auto const &from : T[x])
last = std::max(last, LastTime[from]);
if (last != Time[x]) {
A[x] = Color[last];
Time[x] = last;
}
}
for (valueType i = 1; i <= N; ++i)
std::cout << A[i] << ' ';
std::cout << std::endl;
return 0;
}
[NOI Online #2 提高组] 游戏
考虑计算钦定
分析其复杂度,发现枚举的
剩余的部分直接二项式反演即可,不多赘述。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
namespace MODINT_WITH_FIXED_MOD {
constexpr valueType MOD = 998244353;
template<typename T1, typename T2>
void Inc(T1 &a, T2 b) {
a = a + b;
if (a >= MOD)
a -= MOD;
}
template<typename T1, typename T2>
void Dec(T1 &a, T2 b) {
a = a - b;
if (a < 0)
a += MOD;
}
template<typename T1, typename T2>
T1 sum(T1 a, T2 b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
template<typename T1, typename T2>
T1 sub(T1 a, T2 b) {
return a - b < 0 ? a - b + MOD : a - b;
}
template<typename T1, typename T2>
T1 mul(T1 a, T2 b) {
return (long long) a * b % MOD;
}
template<typename T1, typename T2>
void Mul(T1 &a, T2 b) {
a = (long long) a * b % MOD;
}
template<typename T1, typename T2>
T1 pow(T1 a, T2 b) {
T1 result = 1;
while (b > 0) {
if (b & 1)
Mul(result, a);
Mul(a, a);
b = b >> 1;
}
return result;
}
} // namespace MODINT_WITH_FIXED_MOD
using namespace MODINT_WITH_FIXED_MOD;
class BinomialCoefficient {
private:
valueType N;
ValueVector _Fact, _InvFact;
public:
BinomialCoefficient() = default;
BinomialCoefficient(valueType n) : N(n), _Fact(N + 1, 1), _InvFact(N + 1, 1) {
for (valueType i = 1; i <= N; ++i)
_Fact[i] = mul(_Fact[i - 1], i);
_InvFact[N] = pow(_Fact[N], MOD - 2);
for (valueType i = N - 1; i >= 0; --i)
_InvFact[i] = mul(_InvFact[i + 1], i + 1);
}
valueType operator()(valueType n, valueType m) {
if (n < 0 || m < 0 || n < m)
return 0;
if (m > N)
throw std::out_of_range("BinomialCoefficient::operator() : m > N");
if (n <= N)
return mul(_Fact[n], mul(_InvFact[m], _InvFact[n - m]));
valueType result = 1;
for (valueType i = 0; i < m; ++i)
Mul(result, n - i);
Mul(result, _InvFact[m]);
return result;
}
valueType Fact(valueType n) {
if (n < 0)
return 0;
if (n > N)
throw std::out_of_range("BinomialCoefficient::Fact : n > N");
return _Fact[n];
}
};
valueType N;
ValueMatrix G, F;
ValueVector Size, ZeroCount, OneCount;
ValueVector Type;
void dfs(valueType x, valueType from) {
Size[x] = 1;
ZeroCount[x] = 0;
OneCount[x] = 0;
if (Type[x] == 0)
++ZeroCount[x];
else
++OneCount[x];
F[x][0] = 1;
for (auto const &to : G[x]) {
if (to == from)
continue;
dfs(to, x);
ValueVector const PreF = F[x];
for (valueType i = 0; i <= Size[x] / 2; ++i) {
for (valueType j = 1; j <= Size[to] / 2; ++j)
Inc(F[x][i + j], mul(PreF[i], F[to][j]));
}
Size[x] += Size[to];
ZeroCount[x] += ZeroCount[to];
OneCount[x] += OneCount[to];
}
for (valueType i = std::min(Size[x] / 2, (Type[x] == 0 ? OneCount[x] : ZeroCount[x])); i >= 1; --i) {
if (Type[x] == 0)
Inc(F[x][i], mul(F[x][i - 1], OneCount[x] - (i - 1)));
else
Inc(F[x][i], mul(F[x][i - 1], ZeroCount[x] - (i - 1)));
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::cin >> N;
G.resize(N + 1);
F.resize(N + 1, ValueVector(N + 1, 0));
Size.resize(N + 1);
ZeroCount.resize(N + 1);
OneCount.resize(N + 1);
Type.resize(N + 1);
for (valueType i = 1; i <= N; ++i) {
char c;
std::cin >> c;
Type[i] = c == '0' ? 0 : 1;
}
for (valueType i = 1; i < N; ++i) {
valueType u, v;
std::cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
BinomialCoefficient C(N);
for (valueType i = 0; i <= N / 2; ++i)
Mul(F[1][i], C.Fact(N / 2 - i));
ValueVector Ans(N + 1, 0);
for (valueType i = 0; i <= N / 2; ++i) {
for (valueType j = i; j <= N / 2; ++j) {
if ((j - i) & 1) {
Dec(Ans[i], mul(F[1][j], C(j, i)));
} else {
Inc(Ans[i], mul(F[1][j], C(j, i)));
}
}
}
for (valueType i = 0; i <= N / 2; ++i)
std::cout << Ans[i] << '\n';
std::cout << std::flush;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?