CF1097D Makoto and a Blackboard
首先看着道题直接搞并不是很好搞.
于是我们初步的有一个思路:先将\(n\)分解质因数成
\[N=\Pi_{i=1}^{k} p_i^{x_i}
\]
的形式,然后再对于每一个\(p^x\)计算答案,再将答案合并.
我们先来解决如何合并的问题.
对于一次操作,我们可以将其理解为对于每一个质因子的次数\(x_i\),将其替换为区间\([0,x_i]\)中的任意一个数,记为\(x'\).
所以\(N\)操作一次后应变为
\[N'=\Pi _{i=1}^{k} p_i^{x_i'}
\]
概率显然为\(\Pi_{i=1}^{k}\frac1{x_i+1}\).
这也可以看成\(k\)个\(p_i\)的操作一次的概率之积.
显然这个可以推广.
我们再来看看如何计算每一个\(p_i\)的答案.
设\(dp[s][j]\)表示当前已经操作了\(j\)次,操作后的数为\(p_i^s\)的概率.
显然有状态转移方程\(dp[s][j]=\sum_{l=s}^{x_i}\frac{dp[l][j-1]}{l+1}\),初始状态为\(dp[x_i][0]=1\).
\(\therefore ans_i=\sum_{j=0}^{x_i}dp[k][j]*p^j\)
最终的答案即为\(\Pi_{i=1}^{k}ans_i\).
#include<bits/stdc++.h>
#define il inline
#define rg register
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int O = 1e6 + 10, K = 1e4 + 10;
template<class TT>
il TT read() {
TT o = 0, fl = 1; char ch = getchar();
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') fl = -1, ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl * o;
}
ll n, ans = 1ll, res, dp[51], inv[51], val[O];
int k, tot, cnt[O];
il void pre(ll X) {
for (ll i = 2ll; i * i <= X; ++i)
if (X % i == 0){
val[++tot] = i;
while (X % i == 0) X /= i, ++cnt[tot];
}
if (X ^ 1) val[++tot] = X, cnt[tot] = 1;
inv[0] = inv[1] = 1;
for (int i = 2; i < 51; ++i) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
int main() {
n = read<ll>(), k = read<int>();
pre(n);
for (int c = 1; c <= tot; ++c) {
res = 0; memset(dp, 0, sizeof dp); dp[cnt[c]] = 1;
for (int i = 1; i <= k; ++i)
for (int j = 0; j <= cnt[c]; ++j) {
(dp[j] *= inv[j + 1]) %= mod;
for (int k = j + 1; k <= cnt[c]; ++k)
(dp[j] += dp[k] * inv[k + 1] % mod) %= mod;
}
ll bin = 1, tmp = val[c] % mod;
for (int i = 0; i <= cnt[c]; ++i, (bin *= tmp) %= mod)
(res += dp[i] * bin % mod) %= mod;
(ans *= res) %= mod;
}
printf("%lld", ans);
return 0;
}