[日常训练] Surprise me
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                [日常训练] Surprise me
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                【問題描述】
- 眾所周知,clyz 的紅太陽 cyx 非常喜歡數學,而 zpyz 的 syx 非常喜歡樹。有一天,cyx 和 syx 一起畫了一棵帶有數字的樹。具體的,這棵樹一共有 nnn 個節點,第 iii 個節點上寫著數字 aia_iai?。但是如果只是畫了一棵樹的話,顯然是非常的 boring,于是cyx從這棵樹上隨機選擇了一個節點 uuu,然后 syx 也學著 cyx 的樣子,在這棵樹上隨機選了一個節點 v(u≠v)v(u \neq v)v(u??=v)。cyx 于是說:“我們對選出來的節點定義一個權值吧!”因為 syx 非常地喜歡樹,于是她認為權值一定要是 d(u,v)d(u,v)d(u,v),即樹上兩個點之間最短路的距離。因為 cyx 非常地喜歡數學,所以他認為 syx 的定義過于 naive 了,于是 cyx 認為權值一定要是 φ(au×av)\varphi(a_u \times a_v)φ(au?×av?)。兩人爭執不下,最終雙方各讓一步,共同決定權值應為這兩個函數的乘積,即 d(u,v)φ(au×av)d(u, v) \varphi(a_u \times a_v)d(u,v)φ(au?×av?)。
- 那么現在,問題來了,假如 cyx 和 syx 分別從樹上隨機選擇一個點(兩點互不相同),那么得到的權值的期望是多少?由于這個值可能很大,所以你只需要告訴他們這個值mod  (109+7)\mod (10^9+7)mod(109+7) 的結果就行了。具體的,記所有方案的總權值為 PPP,總方案數為 QQQ,顯然 Q=n(n?1)Q = n(n-1)Q=n(n?1),那么你只需要輸出P×Q?1mod  (109+7)P \times Q^{-1}\mod(10^9+7)P×Q?1mod(109+7)的值就行了。
【輸入格式】
- 第一行一個正整數 nnn,表示總的點數。
- 第二行 nnn 個正整數,第 iii 個正整數表示第 iii 個點的權值 aia_iai?。
- 接下來 n?1n - 1n?1 行每行兩個正整數,表示樹上的一條邊。
【輸出格式】
- 一個正整數,表示答案。
【數據規模】
- 有 20% 的數據,滿足 2≤n≤10002 \le n \le 10002≤n≤1000。
- 有 20% 的數據,滿足 2≤n≤500002 \le n \le 500002≤n≤50000 且第 iii 條邊連接點 iii 和 i+1i+1i+1。
- 有 20% 的數據,樹隨機生成。
- 對于全部數據,滿足 2≤n≤2000002 \le n \le 2000002≤n≤200000,111~nnn 的點權剛好組成一個 111~nnn 的排列。
【分析】
 
 
【代碼】
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cctype> #include <cmath> #include <ctime>const int S = 1 << 20; char frd[S], *ihead = frd + S; const char *itail = ihead;inline char nxtChar() {if (ihead == itail) fread(frd, 1, S, stdin), ihead = frd;return *ihead++; }template <class T> inline void read(T &res) {char ch;while (ch = nxtChar(), !isdigit(ch));res = ch ^ 48;while (ch = nxtChar(), isdigit(ch))res = res * 10 + ch - 48; }const int mod = 1e9 + 7; const int N = 2e5 + 5; const int M = 4e5 + 5; int sum[N], f[20][M], pos[N], Log[M], val[N], stk[N]; int dep[N], vir[M], apr[N], dfn[N], low[N]; int pri[N], a[N], phi[N], miu[N], g[N]; int n, pr, vm, ans, tis, top, E; bool vis[N];inline int ksm(int x, int k) {int res = 1;while (k){if (k & 1) res = 1ll * res * x % mod;x = 1ll * x * x % mod; k >>= 1;}return res; }inline void add(int &x, int y) {x += y;x >= mod ? x -= mod : 0; }struct Edge {int to; Edge *nxt; };Edge p[M], *lst[N], *P = p; Edge q[M], *rst[N], *Q = q;inline void Link(int x, int y) {(++P)->nxt = lst[x]; lst[x] = P; P->to = y;(++P)->nxt = lst[y]; lst[y] = P; P->to = x; }inline void Rink(int x, int y) {(++Q)->nxt = rst[x]; rst[x] = Q; Q->to = y; }inline void Dfs(int x, int fa) {f[0][++E] = x;pos[x] = E;dfn[x] = ++tis;dep[x] = dep[fa] + 1;for (Edge *e = lst[x]; e; e = e->nxt){int y = e->to;if (y == fa) continue;Dfs(y, x);f[0][++E] = x;}low[x] = tis; }inline void Dfs2(int x) {sum[x] = val[x];for (Edge *e = rst[x]; e; e = e->nxt){int y = e->to;Dfs2(y);ans = (1ll * (mod - 4) * dep[x] % mod * sum[x] % mod * sum[y] + ans) % mod;add(sum[x], sum[y]);} }inline bool cmp(const int &x, const int &y) {return dfn[x] < dfn[y]; }inline bool check_Sub(int x, int y) {return dfn[y] >= dfn[x] && dfn[y] <= low[x]; }inline int idMin(int x, int y) {return dep[x] < dep[y] ? x : y; }inline int query_LCA(int x, int y) {if (x > y) std::swap(x, y);int k = Log[y - x + 1];return idMin(f[k][x], f[k][y - (1 << k) + 1]); }int main() {freopen("sm.in", "r", stdin);freopen("sm.out", "w", stdout);read(n);for (int i = 1; i <= n; ++i)read(a[i]), apr[a[i]] = i;for (int i = 1, x, y; i < n; ++i){read(x); read(y);Link(x, y);}Dfs(1, 0);Log[0] = -1;for (int i = 1; i <= E; ++i)Log[i] = Log[i >> 1] + 1;for (int j = 1, jm = Log[E]; j <= jm; ++j) for (int i = 1; i + (1 << j) - 1 <= E; ++i)f[j][i] = idMin(f[j - 1][i], f[j - 1][i + (1 << j - 1)]);phi[1] = miu[1] = 1;for (int i = 2; i <= n; ++i){if (!vis[i]){pri[++pr] = i;phi[i] = i - 1;miu[i] = -1;}for (int j = 1; j <= pr && 1ll * pri[j] * i <= n; ++j){int tmp = pri[j] * i;vis[tmp] = true;if (i % pri[j] == 0){miu[tmp] = 0;phi[tmp] = phi[i] * pri[j];break;}miu[tmp] = -miu[i];phi[tmp] = phi[i] * (pri[j] - 1);}}for (int i = 2; i <= n; ++i)if (miu[i] < 0) miu[i] += mod;for (int i = 1; i <= n; ++i){ int res = 0; vm = 0;for (int j = i; j <= n; j += i)vir[++vm] = apr[j];std::sort(vir + 1, vir + vm + 1, cmp);for (int j = 1, jm = vm; j < jm; ++j)vir[++vm] = query_LCA(pos[vir[j]], pos[vir[j + 1]]);vir[++vm] = 1;std::sort(vir + 1, vir + vm + 1, cmp);vm = std::unique(vir + 1, vir + vm + 1) - vir - 1;for (int j = 1, x; x = vir[j], j <= vm; ++j)val[x] = a[x] % i == 0 ? phi[a[x]] : 0;stk[top = 1] = vir[1];for (int j = 2; j <= vm; ++j){while (top && !check_Sub(stk[top], vir[j])) --top;Rink(stk[top], vir[j]);stk[++top] = vir[j];} ans = 0;Dfs2(1);for (int j = 1, x; x = vir[j], j <= vm; ++j)if (val[x]){int tmp = sum[1];add(tmp, mod - val[x]);ans = (2ll * tmp * val[x] % mod * dep[x] + ans) % mod;}g[i] = ans; for (int i = 1; i <= vm; ++i)sum[vir[i]] = 0, rst[vir[i]] = NULL; Q = q;}for (int i = 1; i <= n; ++i){int tmp = 1ll * i * ksm(phi[i], mod - 2) % mod, res = 0;for (int j = i; j <= n; j += i)res = (1ll * miu[j / i] * g[j] + res) % mod;ans = (1ll * res * tmp + ans) % mod;}printf("%d\n", 1ll * ans * ksm(1ll * n * (n - 1) % mod, mod - 2) % mod); }總結
以上是生活随笔為你收集整理的[日常训练] Surprise me的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: [转贴]犯贱报(一张浓缩大学生活的..)
- 下一篇: gbase数据库中快速备份数据用法
