hdu4935 Prime Tree(2014多校联合第七场)

首先这是一道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 }
View Code
原文地址:https://www.cnblogs.com/astoninfer/p/4947470.html