hdu 5468(莫比烏斯+搜尋)
阿新 • • 發佈:2019-01-24
Sample Input
5 1 2 1 3 2 4 2 5 6 2 3 4 5Sample Output
Case #1: 1 1 0 0 0題意:在一棵樹上,每個節點有值,求以x為根節點的樹中,有多少與根節點互質
思路:
用num[i]記錄節點中包含因子i的個數,然後搜尋到當前根節點時,我們先記錄下在此之前的num,然後遍歷返回後,
計算num的差值,利用莫比烏斯原理,先ans記錄樹中所有的節點數,然後該加的加,該減的減。
莫比烏斯不清楚的話可以翻翻前面的文章。
參考以下大大博文:
/* 如果互質,找出子樹中包含val[cur]的因子的數,假設為6,則減去約數中含有2,3的 但是會重複減去含有6的,所以應該在加上含6的數 於是滿足了莫比烏斯函式,合數為0,含奇數個質數為-1,含偶數個質數為1 感覺特別適合容斥原理。 對於dfs序:/*並不瞭解,也可以做的 將樹展現在陣列上。 void DFS(int u, int fa) { dfn ++; seq[dfn] = u; for(int i = HEAD[u]; i != -1; i = E[i].next) { int v = E[i].to; if(v != fa) DFS(v, u); } dfn ++; seq[dfn] = -u; } 參考: AOQNRMGYXLMV:http://www.cnblogs.com/AOQNRMGYXLMV/p/4858452.html Tc_To_Top:http://blog.csdn.net/tc_to_top/article/details/48802683 */ #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <vector> #include <algorithm> #include <functional> typedef long long ll; using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 100000; int is_prime[maxn+10]; int prime[maxn+10]; int mu[maxn+10]; int snum[maxn+10]; vector<int> fac[maxn + 10]; vector<int> F[maxn+10]; int tot; void Moblus() { tot = 0; memset(is_prime,0,sizeof(is_prime)); mu[1] = 1; for(int i = 2; i <= maxn; i++) { if(!is_prime[i]) { prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot; j++) { if(prime[j]*i>maxn) break; is_prime[i*prime[j]] = 1; if(i % prime[j]) { mu[i*prime[j]] = -mu[i]; } else { mu[i*prime[j]] = 0; break; } } } for(int i = 2; i <= maxn; i++) { if(mu[i]) for(int j = i; j <= maxn; j+=i) fac[j].push_back(i); } } int val[maxn],num[maxn],ans[maxn]; void dfs(int cur,int par) { snum[cur] = 1; vector<int>tt; for(int i = 0; i<fac[val[cur]].size(); i++) { int v = fac[val[cur]][i]; tt.push_back(num[v]); num[v]++; } for(int i = 0; i < F[cur].size(); i++) { int v = F[cur][i]; if(v == par) continue; dfs(v,cur); snum[cur] += snum[v]; } ans[cur] = snum[cur]; for(int i = 0; i<fac[val[cur]].size(); i++) { int v = fac[val[cur]][i]; int c = num[v]-tt[i]; if(c) ans[cur] += mu[v]*c; } } void ini() { tot= 0; memset(ans,0,sizeof(ans)); memset(num,0,sizeof(num)); //memset(head,-1,sizeof(head)); } int main() { int n; Moblus(); int cas = 1,a,b; while(scanf("%d",&n) != EOF) { ini(); for(int i = 0;i <= n;i++) F[i].clear(); for(int i = 0; i <n-1; i++) { scanf("%d%d",&a,&b); F[a].push_back(b); F[b].push_back(a); } for(int i = 1 ; i <= n; i++) scanf("%d",&val[i]); dfs(1,0); printf("Case #%d:",cas++); for(int i = 1; i <= n; i++) { printf(" %d",ans[i]); } printf("\n"); } return 0; }