[COCI2022-2023#3] Bomboni
这题放普及组 t4 刚刚好。
的做法相信大家都能做出来,这里就不讲了。
一个数的因数个数肯定不会太多。查阅经典表格发现 范围内因数最多的数,其因子只有 个。
若两个数相乘后是否能被 整除,只和这个两个数与 的 有关,而与 互质的部分不会发挥作用,对后续计算不会产生影响。
综上,设已经走过的路径上所有数的乘积为 。我们设计 的第三个维度 为满足 的方案个数。最后的答案即 。
using mi = modint<998244353>;
int main(void) {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
size_t n;
ui h;
fin >> n >> h;
vector<ui> d;
array<size_t, size_t(1e6) + 1> rd;
rd.fill(~0);
for (ui i = 1; i <= h; ++i)
if (h % i == 0) rd[i] = d.size(), d.emplace_back(i);
vector<ui> gcd(h);
for (ui i = 0; i < h; ++i) gcd[i] = rd[__gcd(i, h)];
vector<vector<ui>> mp(n, vector<ui>(n));
for (auto& i : mp)
for (auto& j : i) {
int x;
fin >> x;
j = x;
}
auto calc = [&d, h, &gcd](vector<mi> const& f, ui v) {
if (!~v) return vector<mi>(d.size());
vector<mi> g(d.size());
for (size_t i = 0; i < d.size(); ++i) g[gcd[(uli)d[i] * v % h]] += f[i];
return g;
};
auto merge = [](vector<mi> f, vector<mi> const& g) {
for (size_t i = 0; i < f.size(); ++i) f[i] += g[i];
return f;
};
vector<vector<vector<mi>>> dp(n, vector<vector<mi>>(n));
dp[0][0] = vector<mi>(d.size()), dp[0][0][gcd[mp[0][0] % h]] = 1;
for (size_t i = 1; i < n; ++i) dp[0][i] = calc(dp[0][i - 1], mp[0][i]);
for (size_t i = 1; i < n; ++i) dp[i][0] = calc(dp[i - 1][0], mp[i][0]);
for (size_t i = 1; i < n; ++i)
for (size_t j = 1; j < n; ++j)
dp[i][j] =
merge(calc(dp[i][j - 1], mp[i][j]), calc(dp[i - 1][j], mp[i][j]));
fout << dp.back().back().back();
return 0;
}