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;
}
posted @ 2019-11-05 15:28  wuhan2005  阅读(104)  评论(0编辑  收藏  举报