UVA - 11762
Description
Dilu have learned a new thing about integers, which is - any positive integer greater than 1 can be divided by at least one prime number less than or equal to that number. So, he is now playing with this property. He selects a number N. And he calls this D. In each turn he randomly chooses a prime number less than or equal to D. If D is divisible by the prime number then he divides D by the prime number to obtain newD. Otherwise he keeps the old D. He repeats this procedure until D becomes 1. What is the expected number of moves required for N to become 1. [We say that an integer is said to be prime if its divisible by exactly two different integers. So, 1 is not a prime, by definition. List of first few primes are 2, 3, 5, 7, 11, …]
InputInput will start with an integer T (T <= 1000), which indicates the number of test cases. Each of the next T lines will contain one integer N (1 <= N <= 1000000).
OutputFor each test case output a single line giving the case number followed by the expected number of turn required. Errors up to 1e-6 will be accepted.
Sample Input Output for Sample Input
Problemsetter: Md. Arifuzzaman Arif Special Thanks: Sohel Hafiz Source Root :: AOAPC I: Beginning Algorithm Contests -- Training Guide (Rujia Liu) :: Chapter 2. Mathematics :: Probability :: Examples Root :: Prominent Problemsetters :: Md. Arifuzzaman Arif |
题意:
给出一个整数n,每次可以在不超过n的素数中选择一个p,如果p是n的约数,则把n变成n/p,否则n不变。问平均情况下,需要多少次随机选择才能把n变为1。
随机状态转移机
这样的随机过程称为马尔可夫过程(markov process)
设f(x)表示x变成1的随机选择期望次数
根据全期望可得:
f(x) = f(x) * (1 - g(x)/p(x)) + ∑(f(x/i) * (1/p(x)) + 1
其中p(x)表示不超过x的素数数量,g(x)表示不超过x的素数并且是x约数的数量
i为不超过x的素数并且是x约数
因为等式两边都有f(x),移项整理可得:
f(x) = ( p(x) + ∑f(x/i) ) / g(x)
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const double PI = (4.0*atan(1.0));
const int maxn = 1000000 + 20;
const int maxp = 100000;
int vis[maxn];
int prime[maxp];
double dp[maxn];
int primNum;
void sieve(int n) {
int m = (int) sqrt(n + 0.5);
memset(vis, 0, sizeof(vis));
for(int i=2; i<=m; i++) if(!vis[i]) {
for(int j=i*i; j<=n; j+=i) vis[j] = 1;
}
}
int getPrimes(int n) {
sieve(n);
int c = 0;
for(int i=2; i<=n; i++) if(!vis[i])
prime[c++] = i;
return c;
}
double f(int n) {
if(n == 1) return 0;
if(vis[n]) return dp[n];
vis[n] = 1;
int p = 0;
int g = 0;
double ans = 0;
for(int i=0; i<primNum && prime[i] <= n; i++) {
p++;
if(n % prime[i] == 0) {
g++;
ans += f(n/prime[i]);
}
}
return dp[n] = (p + ans) / g;
}
int main() {
int T;
primNum = getPrimes(maxn-1);
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
scanf("%d", &T);
for(int kase=1; kase<=T; kase++) {
int n;
scanf("%d", &n);
double ans = f(n);
printf("Case %d: %.10lf\n", kase, ans);
}
return 0;
}