Puzzled Elena
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2103 Accepted Submission(s): 731
Problem Description
Since both Stefan and Damon fell in love with Elena, and it was really difficult for her to choose. Bonnie, her best friend, suggested her to throw a question to them, and she would choose the one who can solve it.
Suppose there is a tree with n vertices and n - 1 edges, and there is a value at each vertex. The root is vertex 1. Then for each vertex, could you tell me how many vertices of its subtree can be said to be co-prime with itself?
NOTES: Two vertices are said to be co-prime if their values' GCD (greatest common divisor) equals 1.
Input
There are multiply tests (no more than 8).
For each test, the first line has a number n (1≤n≤105), after that has n−1 lines, each line has two numbers a and b (1≤a,b≤n), representing that vertex a is connect with vertex b. Then the next line has n numbers, the ith number indicates the value of the ith vertex. Values of vertices are not less than 1 and not more than 105.
Output
For each test, at first, please output "Case #k: ", k is the number of test. Then, please output one line with n numbers (separated by spaces), representing the answer of each vertex.
Sample Input
5
1 2
1 3
2 4
2 5
6 2 3 4 5
Sample Output
Case #1: 1 1 0 0 0
Source
2015 ACM/ICPC Asia Regional Shanghai Online
题解
- 可以先参考HDU4135:求解区间[a,b]中与k互质的数的个数
- 做这一题之前可以先解决一个问题:给定任意一个序列,求解k与这个序列互质的数的个数。
举个?:求8,9,12总与3互质的数的个数
我们先统计出质因数
8有质因数2,所以p[2]++;
9有质因数3,所以p[3]++;
12有质因数2,3,所以p[2]++,p[3]++;
所以与3不互质的数的个数为p[3] = 2个(9和12各贡献出了一个3,所以他们与3都不互质)
所以与3互质的数的个数为3 - 2 = 1;
每个质因数可以理解为贡献了一个数
- 这一题也类似,先DFS序一遍。具体代码参考如下
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
int const N = 100000 + 10;
int ne[2*N],to[2*N],first[N],w[N],ans[N],cnt[N];
int tot,n;
vector<int>v[N];
void add(int x,int y){
ne[++tot] = first[x];
to[tot] = y;
first[x] = tot;
}
void Pre(){
for(int k=1;k<N;k++){
int n = k;
for(int i=2;(ll)i*i<=n;i++){
if(n % i == 0){
v[k].push_back(i);
while(n % i == 0) n /= i;
}
}
if(n > 1) v[k].push_back(n);
}
}
int cal(int u,int k){
int num = v[u].size(); //u的质因数的个数
int ans = 0;
for(int i=1;i<(1<<num);i++){
int mul = 1,bit = 0;
for(int j=0;j<num;j++)
if(i&(1<<j)){
mul *= v[u][j];
bit++;
}
if(bit&1) ans += cnt[mul];
else ans -= cnt[mul];
cnt[mul] += k;
}
return ans;
}
int DFS(int u,int fa){
int pre = cal(w[u],0);
int s = 0;
for(int i=first[u];i;i=ne[i]){
int v = to[i];
if(v == fa) continue;
s += DFS(v,u);
}
int last = cal(w[u],1);
ans[u] = s - (last - pre); //u子树中结点的个数 - 与u不是互质的结点的个数
if(w[u] == 1) ans[u]++; //1与本身互质 ==(包括字树与前面的与u不互质的结点的个数-前面与u不互质的结点的个数)
return s+1; //返回结点个数(包括自己)
}
int main(){
int caser = 0;
Pre();
while(~scanf("%d",&n)){
memset(cnt,0,sizeof(cnt));
tot = 0;
memset(first,0,sizeof(first));
for(int i=1;i<=n-1;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
DFS(1,0);
printf("Case #%d:",++caser);
for(int i=1;i<=n;i++) printf(" %d",ans[i]);
printf("\n");
}
return 0;
}