CF1842G Tenzing and Random Operations 题解
非常好题目。
我们考虑计算出所有可行的答案最后除以
考虑一个简单的 dp 设计。令
转移是每次加入一个数或者直接乘转移到下一个位置。你发现这个复杂度直接爆炸了,因为
我们希望把状态从
考虑使用乘法分配律。但是暴力展开之后实际上并不好处理。我们继续观察一下,考虑每次操作对每个位置产生的影响,也就是下面这张表格:
我们最后要算的就是每一行的和乘起来。观察这张表格,我们有一个重要的发现:对于乘法分配律展开之后的每一项,你最多会收到来自
换句话说,其余的操作具体是在哪个位置开始的,我们并不关心。
因此,我们可以令
转移有三种:
- 直接选择
。此时乘上 转移即可。 - 选择之前贡献过的某个
,此时乘上 转移即可。 - 选择一个新的
。此时我们有 个操作可以进行选择,因为这个元素必须在当前元素之前做出贡献,因此一共有 个可行的位置,此时乘上 转移到下一个位置即可。
最后对于
还有另外一个组合意义的版本可以用来辅助理解。
假设你需要从
考虑把
假设你在某些位置使用了某些道具,最后你从
你需要对所有使用道具的情况求出从
三种转移可以如下对应:
- 直接选择
。对应走原来的路。 - 选择之前贡献过的某个
。对应选择之前用过的某个道具创造出来的路。 - 选择一个新的
。对应走一个之前放下来,但是从来没有用过的道具创造出来的路。
直接进行这个 dp 复杂度就是
```cpp
#include
#include
using uint = unsigned int; using ll = long long; using ull = unsigned long long;
namespace maths { template <ull mod, class int_type = ll, class uint_type = ull> class modular { private: uint_type x; void norm() { x -= mod * (x >= mod); }
public: modular() : x(0) {} modular(int_type _x) { if (_x < 0) { x = _x % (int_type)mod + (int_type)mod; } else { x = _x % mod; } norm(); return; } friend modular operator+(const modular &lhs, const modular &rhs) { modular ret; ret.x = lhs.x + rhs.x; ret.norm(); return ret; } friend modular operator-(const modular &lhs, const modular &rhs) { modular ret; ret.x = lhs.x + mod - rhs.x; ret.norm(); return ret; } friend modular operator(const modular &lhs, const modular &rhs) { return modular(lhs.x rhs.x); } modular operator-() const { modular ret; ret.x = mod - x; return ret; } modular operator-=(const modular &b) { return this = this - b; } modular operator+=(const modular &b) { return this = this + b; } modular operator=(const modular &b) { return this = this b; } bool operator==(const modular &b) const { return x == b.x; } uint_type val() const { return x; } friend std::istream &operator>>(std::istream &is, modular &rhs) { is >> rhs.x; rhs.x %= mod; return is; } friend std::ostream &operator<<(std::ostream &os, const modular &rhs) { os << rhs.val(); return os; } };
using modint998244353 = modular<998244353>; using modint1000000007 = modular<1000000007>; } // namespace maths
namespace maths { template
template
} // namespace maths
namespace solve { void solve() { using mll = maths::modint1000000007; const uint mod = 1e9 + 7; uint n, m, val; std::cin >> n >> m >> val; std::vector
std::vector<std::vector<mll>> dp(n + 1, std::vector<mll>(n + 1)); dp[0][0] = 1; for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < n; j++) { if (dp[i][j] == 0) { continue; } dp[i + 1][j] += dp[i][j] * (v[i] + mll(val) * j); dp[i + 1][j + 1] += dp[i][j] * (i + 1) * mll(m - j) * val; } } mll ans = 0; const mll inv_n = maths::quick_pow<mll>(n, mod - 2, 1); for (size_t i = 0; i <= n; i++) { ans += maths::quick_pow<mll>(n, m - i, 1) * dp[n][i]; } ans *= maths::quick_pow<mll>(inv_n, m, 1); std::cout << ans << std::endl; } } // namespace solve
int main() { solve::solve(); return 0; }