首先这是一道dp题,对题意的把握和对状态的处理是解题关键。
题目给出的范围是n在1到1e11之间,由于在裂变过称中左儿子总是父亲节点的一个非平凡约数,容易看出裂变过程只与
素数幂有关,并且显然有素数不超过11个,幂指数不超过40,实际上可以用一个大小为11的数组来等价地表示状态,状态
与其内元素顺序无关,因此可以排序,压缩后的状态不超过3000个(准确地说是2957个,通过一个简单的dfs即可统计出此结果)。
以上解决了题目的规模问题。
这道题目我开始因为理解错题意wa了几次,不能通过统计儿子节点的期望高度的平均值再加1得到以父节点为根的数的期望高度,因为两颗子树
的高度在概率上对根树的影响不是相互独立的。
可以设dp(i, j)为以状态i为根深度为j的概率:
那么显然有dp(i, j) = sigma(dp(k, j - 1) * sigma(i / k, t) + sigma(k, t) * dp(i / k, j - 1) + dp(k, j - 1) * dp(i / k, j -1)) / (N - 2)
其中k | i, 且 k ≠ 1,k≠ i, t < j - 1。
以状态i为根的树的期望高度:exp(i) = sigma(j * dp(i, j)), 0 < j < 40.
因此状态转移可以通过枚举左儿子得到,整体复杂度O(3000 * 3000 * 40)。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 #include <string> 6 #include <vector> 7 #include <set> 8 #include <cmath> 9 #include <ctime> 10 #include <cassert> 11 #pragma comment(linker, "/STACK:102400000,102400000") 12 #define lson (u << 1) 13 #define rson (u << 1 | 1) 14 #define cls(i, j) memset(i, j, sizeof i) 15 using namespace std; 16 typedef __int64 ll; 17 const double eps = 1e-6; 18 const double pi = acos(-1.0); 19 const int maxn = 1e5 + 10; 20 const int maxm = 1050; 21 const int inf = 0x3f3f3f3f; 22 const ll linf = 0x3fffffffffffffff; 23 const ll mod = 1e9 + 7; 24 25 int debug = 0; 26 map<ll, int> mapi; 27 int buf[11], k1; 28 ll S = (ll)1e11; 29 double dp[3000][40]; 30 31 int a[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; 32 bool cmp(int a, int b) { return a > b; } 33 int prime[maxn], k; 34 bool vis[3000]; 35 36 ll Hash(int *t){ 37 ll tem = 1, ans = 0; 38 for(int i = 0; i < 11; i++){ 39 ans += tem * t[i]; 40 tem *= 37; 41 } 42 return ans; 43 } 44 45 int stack[11], k2; 46 ll states[3000]; 47 int ks; 48 int table[3500][11]; 49 50 void dfs(ll num, int limit, int next){ 51 if(next){ 52 memcpy(buf, stack, sizeof buf); 53 sort(buf, buf + 11, cmp); 54 ll hash_value = Hash(buf); 55 states[ks++] = hash_value; 56 memcpy(table[ks - 1], buf, sizeof buf); 57 mapi[hash_value] = ks - 1; 58 } 59 if(next > 10) return; 60 for(int i = 1; i <= limit; i++){ 61 num *= a[next]; 62 if(num > S) break; 63 stack[k2++] = i; 64 dfs(num, i, next + 1); 65 stack[--k2] = 0; 66 } 67 } 68 69 void shaffix(){ 70 bool vis[500000 + 10]; 71 int mid = (int)5e5 + 10; 72 cls(vis, 0); 73 for(int i = 2; i < mid; i++){ 74 if(vis[i]) continue; 75 prime[k++] = i; 76 for(ll j = (ll)i * 2; j < mid; j += i) vis[j] = 1; 77 } 78 } 79 80 void cal(int id); 81 82 void dfs1(int id, int next){ 83 if(next > 10){ 84 int buf1[11], buf2[11]; 85 memcpy(buf1, stack, sizeof stack); 86 for(int i = 0; i < 11; i++) buf2[i] = table[id][i] - buf1[i]; 87 sort(buf1, buf1 + 11, cmp); 88 sort(buf2, buf2 + 11, cmp); 89 if(!buf1[0] || !buf2[0]) return; 90 ll hash_value1 = Hash(buf1), hash_value2 = Hash(buf2); 91 int id1 = mapi[hash_value1], id2 = mapi[hash_value2]; 92 cal(id1), cal(id2); 93 double prefix_left = 0, prefix_right = 0; 94 for(int i = 0; i < 39; i++){ 95 dp[id][i + 1] += dp[id1][i] * prefix_right + 96 prefix_left * dp[id2][i] + dp[id1][i] * dp[id2][i]; 97 prefix_left += dp[id1][i], prefix_right += dp[id2][i]; 98 } 99 return; 100 } 101 for(int i = 0; i <= table[id][next]; i++){ 102 stack[k2++] = i; 103 dfs1(id, next + 1); 104 stack[--k2] = 0; 105 } 106 } 107 108 void cal(int id){ 109 if(vis[id]) return; 110 k2 = 0; 111 dfs1(id, 0); 112 int sum = 1; 113 for(int i = 0; i < 11; i++) sum *= 1 + table[id][i]; 114 sum -= 2; 115 for(int i = 1; i < 40; i++) dp[id][i] /= sum; 116 vis[id] = 1; 117 //printf("%d+ ", id); 118 } 119 120 void init(){ 121 shaffix(); 122 cls(vis, 0); 123 vis[0] = 1; 124 mapi.clear(); 125 //0...10 < 10^11 126 cls(stack, 0); 127 ks = k2 = 0; 128 dfs(1, 40, 0); 129 cls(dp, 0); 130 dp[0][1] = 1; 131 for(int i = 1; i < ks; i++) cal(i); 132 } 133 134 double solve(ll num){ 135 cls(buf, 0); 136 k1 = 0; 137 int mid = (int)sqrt((double)num); 138 for(int i = 0; i < k && prime[i] <= mid; i++){ 139 if(num % prime[i]) continue; 140 while(num % prime[i] == 0) ++buf[k1], num /= prime[i]; 141 mid = (int)sqrt((double)num); 142 k1++; 143 } 144 if(num != 1) buf[k1++] = 1; 145 sort(buf, buf + 11, cmp); 146 ll hash_value = Hash(buf); 147 double ans = 0; 148 int id = mapi[hash_value]; 149 for(int i = 1; i < 40; i++) ans += dp[id][i] * i; 150 return ans; 151 } 152 153 int main(){ 154 //freopen("in.txt", "r", stdin); 155 //freopen("out.txt", "w", stdout); 156 int T, kase = 0; 157 init(); 158 scanf("%d", &T); 159 ll n; 160 while(T--){ 161 scanf("%I64d", &n); 162 double ans = solve(n); 163 printf("Case #%d: %.6f ", ++kase, ans); 164 } 165 return 0; 166 }