Codeforces 1097D Makoto and a Blackboard

Codeforces 1097D Makoto and a Blackboard

题目链接

http://codeforces.com/contest/1097/problem/D

题目大意

给你一个数 $n$,对它进行 $k$ 次操作,每次将它变为一个它的因数。假定每次变换都是等概率的,问最后剩下的数期望是多少。

题目分析

首先考虑使用 $DP$ 来解决这道题,式子还是比较好推的,有

$$f[0][n] = 1$$ $$f[i][n] = \sum\limits_{j | n}{f[i – 1][j] * \frac{1}{d(j)}}$$

但是这个 $DP$ 的复杂度是 $O(kd ^ 2(n))$ 的显然无法满足题意。

继续观察题目,可以注意到,任何两个不同的质因子之间其实是互不影响的。例如,$3$ 的期望剩余数量显然是不受 $2$ 的数量影响的。由此可知,它是个积性函数。

那么也就是需要将 $n$ 分解质因数为 $n = {p_1} ^ {x_1} {p_2} ^ {x_2} … {p_m} ^ {x_m}$。设 $g(x, k)$ 为 $x$ 执行 $k$ 次操作剩余数的期望,则有 $g(n, k) = \prod\limits_{i = 1}^{m}{g({p_i} ^ {x_i}, k)}$

那么对于求 $g({p_i} ^ {x_i}, k)$,可以用之前讨论的那个 $DP$。在 $n$ 为质数的幂时,该 $DP$ 可使用前缀和将复杂度降低到 $kd(n)$,由此一来,本题即可解决

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

long long n, k;
long long mod = 1e9 + 7;

const int maxn = 2e5 + 5;
const int maxm = 1e7 + 5;

vector <long long> vec;

vector <int> e[maxn];

long long f[2][maxn];

long long inv[maxn];

long long cnt[maxn];

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

long long qpow(long long b, long long x){
	long long ret = 1;
	
	while(x){
		if(x & 1){
			ret = ret * b % mod;
		}
		
		b = b * b % mod;
		x >>= 1;
	}
	
	return ret;
}

int main(){
	int i, j, l;
	long long x = 1, y = 0;
	long long ans = 1;
	long long maxx = 0;
	
	cin >> n >> k;
	
	long long tmp = sqrt(n);
	
	for(i=2;i<=tmp;i++){
		if(n % i == 0){
			vec.push_back(i);
			while(n % i == 0){
				n /= i;
				cnt[vec.size() - 1]++;
			}
		}
	}
	
	if(n > 1){
		vec.push_back(n);
		cnt[vec.size() - 1] = 1;
	}
	
	for(i=1;i<=100;i++){
		inv[i] = qpow(i, mod - 2);
	}
	
	for(i=0;i<vec.size();i++){
		memset(f, 0, sizeof(f));
		f[0][cnt[i]] = 1;
	
		for(l=1;l<=k;l++){
			long long t = 0;
			for(j=0;j<=cnt[i];j++){
				f[(l & 1)][j] = 0;
			}
		
			for(j=cnt[i];j>=0;j--){
				t = (t + f[!(l & 1)][j] * inv[j + 1]) % mod;
				f[l & 1][j] = t;
			}
		}
		
		x = 1;
		y = 0;
		
		for(j=0;j<=cnt[i];j++){
			y = (y + (x * f[k & 1][j]) % mod) % mod;
			x = x * vec[i] % mod;
		}
		
		ans = ans * y % mod;
	}
	
	cout << ans % mod << endl;
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据