標籤:acm zoj
首先贊一下題目, 好題
題意:
Marjar University has decided to upgrade the infrastructure of school intranet by using fiber-optic technology. There are N buildings in the school. Each building will be installed with one router. These routers are connected by optical cables in such a way that there is exactly one path between any two routers.
Each router should be initialized with an operating frequency Fi before it starts to work. Due to the limitations of hardware and environment, the operating frequency should be an integer number within [Li, Ri]. In order to reduce the signal noise, the operating frequency of any two adjacent routers should be co-prime.
Edward is the headmaster of Marjar University. He is very interested in the number of different ways to initialize the operating frequency. Please write a program to help him! To make the report simple and neat, you only need to calculate the sum of Fi (modulo 1000000007) in all solutions for each router.
英文自己看, 大概意思就是一棵樹上每個點i可以給一個L[i] ~ R[i]的值, 相鄰的兩個點的值要互質, 問每個點的所有情況的值的和, mod 1000000007
大概思路就是枚舉一個點, 然後枚舉這個點上的值(i), 然後求出這樣的情況有多少種(dp[i]), 那麼這個點上的答案就是 dp[1] * 1 + dp[2] * 2 + dp[3] * 3 + .........
然後就是樹形dp了, 轉移方程就是 dp[i][j] =π{(∑{dp[t][k] | gcd(j, k) == 1}) | i 和 t 相鄰}
但是這樣轉移的複雜度是50 * 50000 * 50000, 就算15秒時限也會逾時
所以我們可以考慮用不互質的來轉移;
設s[i] = ∑dp[i][j]
那麼轉移方程就是 dp[i][j] =π{(s[i] - ∑{dp[t][k] | gcd(j, k) != 1}) | i 和 t 相鄰}
對於dp[i][j],我們可以把 j 質因數分解, 假設 j = p1^e1 * p2^e2 * p3^e3, 50000以內的數最多有6個不同的質因數;
然後我們記錄一下 div[i][k] = ∑{ dp[i][j] | j 是 k 的倍數}, 這個可以nlogn的複雜度處理出來;
這樣 ∑{dp[t][k] | gcd(j, k) != 1} = div[t][p1] + div[t][p2] + div[t][p3] - div[t][p1 * p2] - div[t][p1 * p3] - div[t][p2 * p3] + div[t][p1 * p2 * p3], 這樣可以用容斥原理算了, 複雜度最多為2 ^ 6;
這樣dp一次複雜度大概就是 50 * 50000 * (log50000 + 2^6);
要算50個點的話, 還是會逾時;
但是這是一顆樹, 對每個點都dp一次的話算了很多重複的東西, 所以我們不要每次都去全部dp一次, 例如算完i點的了, 要去算j點的, 假設i j相鄰, 那麼在dp數組中只有i和j的值有變化, 我們就只要再算這兩個點的dp轉移就夠了。
更多細節請看代碼:
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <ctime>#include <vector>using namespace std;typedef long long LL;const int N = 50009;const LL M = 1000000007;inline void addIt(int &a, int b){ a += b; if(a >= M) a -= M;}inline int sub(int a, int b){ a -= b; if(a < 0) a += M; if(a >= M) a -= M; return a;}struct Num{ int p[11]; int allp;}num[N];struct Data{ int dp[N], div[N], all;}data[55], fb[55];int L[55], R[55];int ans[55];int n;vector<int> e[55];bool vis[55];int rcn, rcv;void print(){ for(int i = 0; i < n; i++) { printf("i = %d\n", i); for(int j = 0; j < 6; j++) printf("dp[%d] = %d\n", j, data[i].dp[j]); }}int rc(int i, int xs){ int t, r = 0; for(; i < num[rcn].allp; i++) { if(xs * num[rcn].p[i] <= R[rcv]) t = data[rcv].div[xs * num[rcn].p[i]]; else t = 0; //printf("***%d, t = %d\n", xs * num[rcn].p[i], t); addIt(r, sub(t, rc(i + 1, xs * num[rcn].p[i]))); } //printf("r = %d\n", r); return r;}void dfsTree(int pre, int now){ if(vis[now]) return; vis[now] = true; int i, siz = e[now].size(); for(i = 0; i < siz; i++) dfsTree(now, e[now][i]); if(pre >= 0 && siz <= 1) for(i = L[now]; i <= R[now]; i++) data[now].dp[i] = 1; else for(i = L[now]; i <= R[now]; i++) { data[now].dp[i] = 1; for(int j = 0; j < siz; j++) if(e[now][j] != pre) { rcn = i; rcv = e[now][j]; data[now].dp[i] = (LL)(data[now].dp[i]) * sub(data[e[now][j]].all, rc(0, 1)) % M; } } data[now].all = 0; for(i = 1; i <= R[now]; i++) { data[now].div[i] = 0; for(int j = i; j <= R[now]; j += i) if(j >= L[now]) addIt(data[now].div[i], data[now].dp[j]); if(i >= L[now]) addIt(data[now].all, data[now].dp[i]); }}void dfs(int pre, int now, int deep){ dfsTree(-1, now); //if(now == 1) print(); int i, siz = e[now].size(); ans[now] = 0; for(i = L[now]; i <= R[now]; i++) addIt(ans[now], (LL)data[now].dp[i] * i % M); //fb[deep] = data[now]; //vis[now] = false; for(i = 0; i < siz; i++) if(e[now][i] != pre) { vis[e[now][i]] = false; fb[deep] = data[e[now][i]]; vis[now] = false; dfs(now, e[now][i], deep + 1); data[e[now][i]] = fb[deep]; vis[e[now][i]] = true; }}void init(){ int i, j, k; for(i = 0; i < N; i++) num[i].allp = 0; for(i = 2; i < N; i++) if(num[i].allp == 0) for(j = i; j < N; j += i) num[j].p[num[j].allp++] = i;}int main(){ //freopen("13F.in", "r", stdin); init(); int T; scanf("%d", &T); while(T--) { scanf("%d", &n); int i, j, k; for(i = 0; i < n; i++) { scanf("%d", &L[i]); } for(i = 0; i < n; i++) { scanf("%d", &R[i]); e[i].clear(); } for(i = 0; i < n - 1; i++) { scanf("%d %d", &j, &k); j--; k--; e[j].push_back(k); e[k].push_back(j); } memset(vis, false, sizeof(vis)); memset(data, 0, sizeof(data)); dfsTree(-1, 0); //print(); dfs(-1, 0, 0); for(i = 0; i < n - 1; i++) printf("%d ", ans[i]); printf("%d\n", ans[i]); } return 0;}
2014牡丹江 現場賽 F zoj 3824 Fiber-optic Network