【学习笔记】DP 套 DP
DP 套 DP 的题目一般大致要求为求满足某个要求的元素数量。而对于其要求的判定需要 DP 来解决。因此我们将判定 DP 的结果作为计数 DP 的状态来进行计数。
[TJOI2018] 游园会
首先考虑如何求出两个字符串
我们考虑对上述判定 DP 的过程进行计数,具体的,将上述判定 DP 结果相同的前缀作为相同的子问题进行合并后计数以优化复杂度,但是若直接对于某个
我们可以发现,对于某个
进而我们可以预处理出判定 DP 的转移边,即对于所有可能的
考虑如何处理其中不能出现
至此我们便可以通过此题,复杂度为
Code
#include <bits/stdc++.h>
typedef int 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;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, K;
std::cin >> N >> K;
std::string S_;
std::cin >> S_;
ValueVector Table(1 << 8, -1);
Table['N'] = 0;
Table['O'] = 1;
Table['I'] = 2;
ValueVector S(S_.begin(), S_.end());
for (auto &x : S)
x = Table[x];
ValueMatrix Transfer(1 << K, ValueVector(3, -1));
for (valueType s = 0; s < (1 << K); ++s) {
ValueVector prev(K + 1, 0);
for (valueType i = 1; i <= K; ++i)
prev[i] = (s >> (i - 1)) & 1;
std::partial_sum(prev.begin(), prev.end(), prev.begin());
for (valueType c = 0; c < 3; ++c) {
ValueVector next(K + 1, 0);
for (valueType i = 1; i <= K; ++i) {
next[i] = std::max(prev[i], next[i - 1]);
if (S[i - 1] == c)
next[i] = std::max(next[i], prev[i - 1] + 1);
}
std::adjacent_difference(next.begin(), next.end(), next.begin());
valueType t = 0;
for (valueType i = 1; i <= K; ++i)
t |= next[i] << (i - 1);
Transfer[s][c] = t;
}
}
std::array<ValueMatrix, 2> F;
F[0].resize(1 << K, ValueVector(3, 0));
F[1].resize(1 << K, ValueVector(3, 0));
F[0][0][0] = 1;
for (valueType i = 1; i <= N; ++i) {
valueType const now = i & 1, prev = now ^ 1;
for (auto &v : F[now])
std::fill(v.begin(), v.end(), 0);
for (valueType s = 0; s < (1 << K); ++s) {
for (valueType c = 0; c < 3; ++c) {
valueType const t = Transfer[s][c];
if (c == 0) { // N
Inc(F[now][t][1], F[prev][s][0]);
Inc(F[now][t][1], F[prev][s][1]);
Inc(F[now][t][1], F[prev][s][2]);
}
if (c == 1) { // O
Inc(F[now][t][0], F[prev][s][0]);
Inc(F[now][t][2], F[prev][s][1]);
Inc(F[now][t][0], F[prev][s][2]);
}
if (c == 2) { // I
Inc(F[now][t][0], F[prev][s][0]);
Inc(F[now][t][0], F[prev][s][1]);
}
}
}
}
ValueVector Ans(K + 1, 0);
for (valueType s = 0; s < (1 << K); ++s) {
valueType const popcount = __builtin_popcountll(s);
for (valueType c = 0; c < 3; ++c)
Inc(Ans[popcount], F[N & 1][s][c]);
}
for (valueType i = 0; i <= K; ++i)
std::cout << Ans[i] << std::endl;
return 0;
}
CF979E Kuro and Topological Parity
我们首先考虑在确定节点颜色的情况下如何计数,设
不难发现影响路径总数奇偶性的是奇点个数的奇偶性,而决定一个点奇偶性的是与之相连的异色奇数点个数,这启示我们将黑色奇点和白色奇点的个数作为状态进行奇数,设
现在还剩一个问题,若我们希望新增点数为奇点,那么我们便要选择偶数个异色奇点(该新增点自身为一条路径),设有
我们可以证明其为
因此直接进行转移即可,复杂度为
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;
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;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, P;
std::cin >> N >> P;
ValueCube F;
F.resize(N + 1, ValueMatrix(N + 1, ValueVector(N + 1, 0)));
ValueVector C(N + 1, 0);
for (valueType i = 1; i <= N; ++i)
std::cin >> C[i];
if (N == 1) {
if (P == 0)
std::cout << 0 << std::endl;
else if (C[1] == -1)
std::cout << 2 << std::endl;
else
std::cout << 1 << std::endl;
return 0;
}
// f_{i, j, k} i 个点, j 个奇黑, k 个奇白
if (C[1] != 1)
F[1][1][0] = 1;
if (C[1] != 0)
F[1][0][1] = 1;
for (valueType i = 2; i <= N; ++i) {
for (valueType j = 0; j < i; ++j) {
for (valueType k = 0; j + k < i; ++k) { // 上一位的状态
if (C[i] != 1) { // 0 : 黑
if (k > 0)
Inc(F[i][j + 1][k], mul(F[i - 1][j][k], ((1ll << (i - 2)) % MOD)));
else
Inc(F[i][j + 1][k], mul(F[i - 1][j][k], ((1ll << (i - 1)) % MOD)));
if (k > 0)
Inc(F[i][j][k], mul(F[i - 1][j][k], ((1ll << (i - 2)) % MOD)));
}
if (C[i] != 0) { // 1 : 白
if (j > 0)
Inc(F[i][j][k + 1], mul(F[i - 1][j][k], ((1ll << (i - 2)) % MOD)));
else
Inc(F[i][j][k + 1], mul(F[i - 1][j][k], ((1ll << (i - 1)) % MOD)));
if (j > 0)
Inc(F[i][j][k], mul(F[i - 1][j][k], ((1ll << (i - 2)) % MOD)));
}
}
}
}
valueType ans = 0;
for (valueType j = 0; j <= N; ++j)
for (valueType k = 0; j + k <= N; ++k)
if (((j + k) & 1) == P)
Inc(ans, F[N][j][k]);
std::cout << ans << std::endl;
return 0;
}
[SDOI/SXOI2022] 小 N 的独立集
考虑在给定点权的情况下如何求最大独立集,设
下面考虑如何计数,设
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;
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;
valueType N, K;
ValueMatrix G;
ValueCube F;
ValueVector Size;
void dfs(valueType x, valueType from) {
Size[x] = K;
for (valueType k = 1; k <= K; ++k)
Inc(F[x][0][k], 1);
for (auto const &to : G[x]) {
if (to == from)
continue;
dfs(to, x);
ValueMatrix Next(Size[x] + Size[to] + 1, ValueVector(K + 1, 0));
for (valueType t = 0; t <= Size[x]; ++t) {
for (valueType d_t = 0; d_t <= K && d_t + t <= Size[x]; ++d_t) {
if (F[x][t][d_t] == 0)
continue;
for (valueType s = 0; s <= Size[to]; ++s) {
for (valueType d_s = 0; d_s <= d_t && d_s + s <= Size[to]; ++d_s) {
Inc(Next[s + d_s + t][d_t - d_s], mul(F[x][t][d_t], F[to][s][d_s]));
}
for (valueType d_s = d_t + 1; d_s <= K && d_s + s <= Size[to]; ++d_s) {
Inc(Next[s + d_s + t][0], mul(F[x][t][d_t], F[to][s][d_s]));
}
}
}
}
F[x].swap(Next);
Size[x] += Size[to];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::cin >> N >> K;
G.resize(N + 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); // return 0;
}
F.resize(N + 1, ValueMatrix(N * K + 1, ValueVector(K + 1, 0)));
Size.resize(N + 1, 0);
dfs(1, 0);
ValueVector Ans(N * K + 1, 0);
for (valueType s = 1; s <= N * K; ++s)
for (valueType d = 0; d <= K && s + d <= N * K; ++d)
Inc(Ans[s + d], F[1][s][d]);
for (valueType i = 1; i <= N * K; ++i)
std::cout << Ans[i] << '\n';
std::cout << std::flush;
std::exit(0);
}
CF1784E Infinite Game
首先考虑若确定
发现比分只有
考虑对这个内向基环树森林进行计数,考虑到只有四条边和四个节点,因此我们考虑将其压入状态,设
发现影响复杂度的主要是对边权的统计,考虑压缩这些状态。发现我们实际上要求的是环上的边权和,又考虑到节点个数很少,因此我们可以枚举环上的节点然后只记录环上的边权和。设
复杂度为
Code
#include <bits/stdc++.h>
typedef int 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;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::string S;
std::cin >> S;
valueType const N = S.length();
ValueVector Ans(3, 0);
for (valueType circle = 1; circle < (1 << 4); ++circle) {
ValueMatrix NextWeight(1 << 8, ValueVector(2, 0)), NextState(1 << 8, ValueVector(2, 0));
for (valueType state = 0; state < (1 << 8); ++state) {
for (valueType c = 0; c < 2; ++c) {
for (valueType i = 0; i < 4; ++i) {
valueType to = (state >> (2 * i)) & 3;
if (c == 0) {
if (to & 1) { // 已有分数,获胜一局
if ((circle >> i) & 1) // 在环中
++NextWeight[state][c];
to = 0;
} else { // 获得一分
to |= 1;
}
} else { // c == 1
if (to & 2) {
if ((circle >> i) & 1)
--NextWeight[state][c];
to = 0;
} else {
to |= 2;
}
}
NextState[state][c] |= to << (2 * i);
}
}
}
valueType const Bound = (N + 1) / 2 * 2 * __builtin_popcount(circle);
ValueMatrix F((1 << 8), ValueVector(2 * Bound + 1));
F[3 << 6 | 2 << 4 | 1 << 2 | 0 << 0][Bound] = 1;
for (valueType i = 0; i < N; ++i) {
ValueMatrix Next((1 << 8), ValueVector(2 * Bound + 1, 0));
for (valueType state = 0; state < (1 << 8); ++state) {
for (valueType sum = 0; sum <= 2 * Bound; ++sum) {
if (F[state][sum] == 0)
continue;
for (valueType c = 0; c < 2; ++c) {
if (c == 0 && S[i] == 'b')
continue;
if (c == 1 && S[i] == 'a')
continue;
Inc(Next[NextState[state][c]][sum + NextWeight[state][c]], F[state][sum]);
}
}
}
F.swap(Next);
}
for (valueType state = 0; state < (1 << 8); ++state) { // 检查是否在环上
ValueVector To(4);
for (valueType i = 0; i < 4; ++i)
To[i] = (state >> (2 * i)) & 3;
ValueVector Path({0});
while (true) {
valueType const x = Path.back();
if (std::find(Path.begin(), Path.end(), To[x]) != Path.end()) {
Path.erase(Path.begin(), std::find(Path.begin(), Path.end(), To[x]));
break;
} else {
Path.push_back(To[x]);
}
}
valueType realCircle = 0;
for (auto const &x : Path)
realCircle |= 1 << x;
if (realCircle != circle)
continue;
for (valueType sum = 0; sum <= 2 * Bound; ++sum) {
if (sum == Bound) {
Inc(Ans[1], F[state][sum]);
} else if (sum > Bound) {
Inc(Ans[0], F[state][sum]);
} else {
Inc(Ans[2], F[state][sum]);
}
}
}
}
std::cout << Ans[0] << std::endl;
std::cout << Ans[1] << std::endl;
std::cout << Ans[2] << std::endl;
return 0;
}
[ZJOI2019] 麻将
首先给出一些定义:
-
顺子:三张大小相邻的牌,例如
,其中 。 -
刻子:三张大小相同的牌,例如
,其中 。 -
面子:顺子和刻子的统称。
-
对子:两张大小相同的牌,例如
,其中 。
我们首先考虑如何判断是否胡牌,对于第二种胡牌方法的判断是简单的,主要考虑第一种。
可以发现,若我们最终的组合方式中存在三个顺子,那么我们可以将其转化为三个刻字。因此我们只需要考虑顺子个数小于三个的情况,考虑设
对于牌组中是否存在对子的判断是简单的,在
可以发现上述 DP 的状态数不多,考虑建出自动机后进行计数。暴力进行转移后得到的自动机大约是
考虑到胡牌轮数的期望难以计算,可以转化为求截至第
设
复杂度
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;
typedef std::vector<bool> bitset;
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) const {
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) const {
return Fact_[n];
}
};
class Mahjong {
private:
class State {
protected:
ValueMatrix F;
public:
State() : F(3, ValueVector(3, -1)) {
// F = ValueMatrix(3, ValueVector(3, -1));
}
void SetHu() {
// F = ValueMatrix(3, ValueVector(3, -1));
std::abort();
}
void SetFirst() {
// F = ValueMatrix(3, ValueVector(3, 0));
// F = ValueMatrix(3, ValueVector(3, -1));
for (auto &v : F)
std::fill(v.begin(), v.end(), -1);
F[0][0] = 0;
}
void SetSecond() {
// F = ValueMatrix(3, ValueVector(3, -1));
for (auto &v : F)
std::fill(v.begin(), v.end(), -1);
}
bool CheckHu() const {
for (valueType i = 0; i < 3; ++i)
for (valueType j = 0; j < 3; ++j)
if (F[i][j] >= 4)
return true;
return false;
}
public:
friend bool operator<(State const &a, State const &b) {
// for (valueType i = 0; i < 3; ++i)
// for (valueType j = 0; j < 3; ++j)
// if (a.F[i][j] != b.F[i][j])
// return a.F[i][j] < b.F[i][j];
// return false;
return a.F < b.F;
}
friend bool operator==(State const &a, State const &b) {
return a.F == b.F;
}
friend State operator+(State const &S, valueType count) {
State T;
for (valueType i = 0; i < 3; ++i) {
for (valueType j = 0; j < 3; ++j) {
if (S.F[i][j] == -1)
continue;
for (valueType k = 0; k < 3 && i + j + k <= count; ++k)
T.F[j][k] = std::max(T.F[j][k], std::min<valueType>(4, S.F[i][j] + i + (count - i - j - k) / 3));
}
}
return T;
}
friend State Merge(State const &A, State const &B) {
State result;
for (valueType i = 0; i < 3; ++i)
for (valueType j = 0; j < 3; ++j)
result.F[i][j] = std::max(A.F[i][j], B.F[i][j]);
return result;
}
};
private:
std::pair<State, State> state;
valueType pairCount;
public:
Mahjong() {
SetInit();
};
void SetHu() {
state.first.SetHu();
state.second.SetHu();
pairCount = -1;
}
void SetInit() {
state.first.SetFirst();
state.second.SetSecond();
pairCount = 0;
// pairCount = -1;
}
bool CheckHu() {
if (pairCount >= 7 || state.second.CheckHu()) {
// SetHu();
return true;
} else {
return false;
}
}
public:
friend bool operator<(Mahjong const &a, Mahjong const &b) {
if (a.pairCount == b.pairCount)
return a.state < b.state;
return a.pairCount < b.pairCount;
}
friend bool operator==(Mahjong const &a, Mahjong const &b) {
return a.pairCount == b.pairCount && a.state == b.state;
}
friend Mahjong operator+(Mahjong const &S, valueType count) {
Mahjong T;
T.SetInit();
T.pairCount = std::min<valueType>(7, S.pairCount + (count >= 2 ? 1 : 0));
if (count >= 2) {
T.state.second = Merge(S.state.first + (count - 2), S.state.second + count);
} else {
T.state.second = S.state.second + count;
}
T.state.first = S.state.first + count;
// T.CheckHu();
return T;
}
};
int main() {
auto __begin = std::chrono::steady_clock::now();
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N;
std::cin >> N;
ValueVector Bucket(N + 1, 0);
for (valueType i = 0; i < 13; ++i) {
valueType x, t;
std::cin >> x >> t;
++Bucket[x];
}
std::map<Mahjong, valueType> ID;
valueType size = 0;
ValueMatrix Transfer(4000, ValueVector(5, -1));
bitset Finish(4000, false);
{
std::queue<Mahjong> Q;
Mahjong start;
start.SetInit();
ID[start] = ++size;
Q.push(start);
while (!Q.empty()) {
Mahjong const state = Q.front();
Q.pop();
valueType const x = ID[state];
{
Mahjong temp = state;
if (temp.CheckHu())
Finish[x] = true;
assert(temp == state);
}
for (valueType count = 0; count <= 4; ++count) {
Mahjong const next = state + count;
// if (count == 0)
// assert(next == state);
if (ID.count(next) > 0) {
Transfer[x][count] = ID[next];
} else {
Transfer[x][count] = (ID[next] = ++size);
Q.push(next);
}
}
}
}
std::cerr << "size = " << size << std::endl;
std::cerr << "Time[1] : " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - __begin).count() << "[ms]" << std::endl;
ValueMatrix FastC(5, ValueVector(5, 0));
FastC[0][0] = 1;
for (valueType i = 1; i <= 4; ++i) {
FastC[i][0] = 1;
for (valueType j = 1; j <= i; ++j)
FastC[i][j] = FastC[i - 1][j] + FastC[i - 1][j - 1];
}
ValueMatrix F(4 * N + 1, ValueVector(size + 1, 0));
F[0][1] = 1;
for (valueType i = 1; i <= N; ++i) {
ValueMatrix Next(4 * i + 1, ValueVector(size + 1, 0));
for (valueType j = 0; j <= 4 * (i - 1); ++j) {
valueType k = 1;
// for (valueType k = 1; k <= size; ++k) {
for (k = 1; k + 7 <= size; k += 4) {
// for (valueType t = Bucket[i]; t <= 4; ++t)
// Inc(Next[j + t][Transfer[k][t]], mul(F[j][k], C(4 - Bucket[i], t - Bucket[i])));
switch (Bucket[i]) {
case 0:
Inc(Next[j + 0][Transfer[k + 0][0]], mul(F[j][k + 0], FastC[4 - Bucket[i]][0 - Bucket[i]]));
case 1:
Inc(Next[j + 1][Transfer[k + 0][1]], mul(F[j][k + 0], FastC[4 - Bucket[i]][1 - Bucket[i]]));
case 2:
Inc(Next[j + 2][Transfer[k + 0][2]], mul(F[j][k + 0], FastC[4 - Bucket[i]][2 - Bucket[i]]));
case 3:
Inc(Next[j + 3][Transfer[k + 0][3]], mul(F[j][k + 0], FastC[4 - Bucket[i]][3 - Bucket[i]]));
case 4:
Inc(Next[j + 4][Transfer[k + 0][4]], mul(F[j][k + 0], FastC[4 - Bucket[i]][4 - Bucket[i]]));
}
switch (Bucket[i]) {
case 0:
Inc(Next[j + 0][Transfer[k + 1][0]], mul(F[j][k + 1], FastC[4 - Bucket[i]][0 - Bucket[i]]));
case 1:
Inc(Next[j + 1][Transfer[k + 1][1]], mul(F[j][k + 1], FastC[4 - Bucket[i]][1 - Bucket[i]]));
case 2:
Inc(Next[j + 2][Transfer[k + 1][2]], mul(F[j][k + 1], FastC[4 - Bucket[i]][2 - Bucket[i]]));
case 3:
Inc(Next[j + 3][Transfer[k + 1][3]], mul(F[j][k + 1], FastC[4 - Bucket[i]][3 - Bucket[i]]));
case 4:
Inc(Next[j + 4][Transfer[k + 1][4]], mul(F[j][k + 1], FastC[4 - Bucket[i]][4 - Bucket[i]]));
}
switch (Bucket[i]) {
case 0:
Inc(Next[j + 0][Transfer[k + 2][0]], mul(F[j][k + 2], FastC[4 - Bucket[i]][0 - Bucket[i]]));
case 1:
Inc(Next[j + 1][Transfer[k + 2][1]], mul(F[j][k + 2], FastC[4 - Bucket[i]][1 - Bucket[i]]));
case 2:
Inc(Next[j + 2][Transfer[k + 2][2]], mul(F[j][k + 2], FastC[4 - Bucket[i]][2 - Bucket[i]]));
case 3:
Inc(Next[j + 3][Transfer[k + 2][3]], mul(F[j][k + 2], FastC[4 - Bucket[i]][3 - Bucket[i]]));
case 4:
Inc(Next[j + 4][Transfer[k + 2][4]], mul(F[j][k + 2], FastC[4 - Bucket[i]][4 - Bucket[i]]));
}
switch (Bucket[i]) {
case 0:
Inc(Next[j + 0][Transfer[k + 3][0]], mul(F[j][k + 3], FastC[4 - Bucket[i]][0 - Bucket[i]]));
case 1:
Inc(Next[j + 1][Transfer[k + 3][1]], mul(F[j][k + 3], FastC[4 - Bucket[i]][1 - Bucket[i]]));
case 2:
Inc(Next[j + 2][Transfer[k + 3][2]], mul(F[j][k + 3], FastC[4 - Bucket[i]][2 - Bucket[i]]));
case 3:
Inc(Next[j + 3][Transfer[k + 3][3]], mul(F[j][k + 3], FastC[4 - Bucket[i]][3 - Bucket[i]]));
case 4:
Inc(Next[j + 4][Transfer[k + 3][4]], mul(F[j][k + 3], FastC[4 - Bucket[i]][4 - Bucket[i]]));
}
}
while (k <= size) {
switch (Bucket[i]) {
case 0:
Inc(Next[j + 0][Transfer[k][0]], mul(F[j][k], FastC[4 - Bucket[i]][0 - Bucket[i]]));
case 1:
Inc(Next[j + 1][Transfer[k][1]], mul(F[j][k], FastC[4 - Bucket[i]][1 - Bucket[i]]));
case 2:
Inc(Next[j + 2][Transfer[k][2]], mul(F[j][k], FastC[4 - Bucket[i]][2 - Bucket[i]]));
case 3:
Inc(Next[j + 3][Transfer[k][3]], mul(F[j][k], FastC[4 - Bucket[i]][3 - Bucket[i]]));
case 4:
Inc(Next[j + 4][Transfer[k][4]], mul(F[j][k], FastC[4 - Bucket[i]][4 - Bucket[i]]));
}
++k;
}
// }
}
F.swap(Next);
}
std::cerr << "Time[2] : " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - __begin).count() << "[ms]" << std::endl;
BinomialCoefficient const C(4 * N + 5);
valueType ans = 0;
for (valueType i = 13; i <= 4 * N; ++i) {
valueType sumA = 0, sumB = 0;
for (valueType j = 1; j <= size; ++j) {
Inc(sumA, F[i][j]);
if (!Finish[j])
Inc(sumB, F[i][j]);
}
Inc(ans, mul(sumB, pow(sumA, MOD - 2)));
}
// Mul(ans, pow(C.Fact(4 * N - 13), MOD - 2));
std::cout << ans << std::endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!