[CF1097D]Makoto and a Blackboard

题目

点这里看题目。

分析

\(f_k(n)\) 表示经过了 \(k\) 次操作之后 \(n\) 的期望。

这里有一个很重要的性质:\(f\) 是积性函数

事实上,每次操作就相当于是对 \(n\) 的每一个质因子 \(p_i\) 的指数 \(k_i\) 随机替换为 \([0,k_i]\) 中的一个整数。可以发现各个质因子之间不相干。或者说:

\[\begin{aligned}E(n)&=\sum_{\{k'_i\}}[\forall i,0\le k'_i\le k_i]\prod_{i}\frac{1}{k_i+1}\prod_i p_i^{k'_i}\\&=\sum_{i}\sum_{k'=0}^{k_i} \frac{1}{k_i+1}p_i^{k'}\end{aligned} \]

现在我们就可以将 \(n\) 按照质因子拆开。此时我们只需要求 \(p_i^0,p_i^1,p_i^2,...,p_i^{k_i}\) 的最终出现概率即可。

由于底数相等,现在我们对指数进行 DP 。状态:

\(g(t,j)\) :经过了前 \(j\) 次操作之后,出现 \(p_i^t\) 的概率。

转移略。此时 \(p_i\) 的贡献就是 \(\sum_{k'}f(k',k)\times p_i^{k'}\)

小结:

  1. 将原先的整个数拆分成各个质因子,并利用积性简化成单个质因子的问题,遇到因子相关的问题会很有用。多多观察题目的结果是否具有积性。
  2. 在底数确定的时候直接处理指数,比较常见的技巧。有时候还可以发现它不受 \(k_i\) 的约束,就可以预处理。

代码

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long LL;

const int mod = 1e9 + 7;
const int MAXN = 1e4 + 5, MAXS = 100;

template<typename _T>
void read( _T &x )
{
	x = 0; char s = getchar(); int f = 1;
	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) write( x / 10 );
	putchar( x % 10 + '0' );
}

template<typename _T>
_T MAX( const _T a, const _T b )
{
	return a > b ? a : b;
}

int f[MAXS], inv[MAXS];

int ind[MAXN];
LL prim[MAXN], pn;

LL N; int K, lim;

int Qkpow( int, int );
inline int Mul( LL x, int v ) { return x * v % mod; }
inline int Inv( const int a ) { return Qkpow( a, mod - 2 ); }
inline int Sub( int x, int v ) { return ( x -= v ) < 0 ? x + mod : x; }
inline int Add( int x, int v ) { return ( x += v ) >= mod ? x - mod : x; }

int Qkpow( int base, int indx )
{
	int ret = 1;
	while( indx )
	{
		if( indx & 1 ) ret = Mul( ret, base );
		base = Mul( base, base ), indx >>= 1;
	}
	return ret;
}

void PFactorize( LL n )
{
	for( LL i = 2 ; i * i <= n ; i ++ )
		if( ! ( n % i ) )
		{
			prim[++ pn] = i;
			while( ! ( n % i ) )
				ind[pn] ++, n /= i;
		}
	if( n > 1 ) prim[++ pn] = n, ind[pn] = 1;
}

int Calc( LL p, const int x )
{
	for( int i = 0 ; i <= x ; i ++ ) f[i] = 0;
	f[0] = 1; int tmp;
	for( int k = 1 ; k <= K ; k ++ )
		for( int i = x ; ~ i ; i -- )
		{
			tmp = 0;
			for( int j = i ; ~ j ; j -- )
				tmp = Add( tmp, Mul( inv[x - j + 1], f[j] ) );
			f[i] = tmp;
		}
	int ret = 0, pw = 1; p %= mod;
	for( int i = 0 ; i <= x ; i ++, pw = Mul( pw, p ) )
		ret = Add( ret, Mul( pw, f[x - i] ) );
	return ret;
}

int main()
{
	read( N ), read( K );
	PFactorize( N ); int ans = 1;
	for( int i = 1 ; i <= pn ; i ++ ) lim = MAX( lim, ind[i] );
	for( int i = 1 ; i <= lim + 1 ; i ++ ) inv[i] = Inv( i );
	for( int i = 1 ; i <= pn ; i ++ ) ans = Mul( ans, Calc( prim[i], ind[i] ) );
	write( ans ), putchar( '\n' );
	return 0;
}
posted @ 2020-12-03 15:27  crashed  阅读(71)  评论(0编辑  收藏  举报