原题链接:http://codeforces.com/contest/842/problem/C
题意:一个以1为根节点的树,每个节点有一个值ai,定义美丽度:从根节点到这个节点的路径上所有ai的gcd,即gcd(a1,a2,a5...ai),对每个节点的美丽度,我们可以使根到这个节点的路径上一个点的ai值变为0。求所有点的最大美丽度。
思路:先求出没有节点变为0的情况g[i],在此基础上,如果使x节点变为0,那么它的美丽度为父节点的g[i];假设让其他在路径上的点变为0,可以知道x节点的最大美丽度是a[x]的因子,因此我们只要枚举a[x]的因子,如果这个因子在路径上出现了(深度-1)次,即我们可以把路径上其中一个a[i]变为0,剩下的a[]值都含有上述因子,那么最大美丽度一定不小于这个因子。按这个方法跑一遍dfs就行了。
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<map> 6 using namespace std; 7 const int MAXN=2e5+5; 8 int num[MAXN],res[MAXN],mp[MAXN],g[MAXN]; 9 vector<int> edge[MAXN]; 10 bool vis[MAXN]; 11 int gcd(int a, int b){ 12 return (b==0)?a:gcd(b, a%b); 13 } 14 void dfs(int fa, int depth){ 15 int l=edge[fa].size(); 16 int u,k; 17 for(int i=0;i<l;i++) 18 { 19 u=edge[fa][i]; 20 k=num[u]; 21 if(!vis[u]){ 22 vis[u]=1; 23 g[u]=gcd(k, g[fa]); 24 res[u]=g[fa]; 25 for(int j=1;j*j<=k;j++){ 26 if(k%j==0){ 27 mp[j]++; 28 if(mp[j]>=depth-1) res[u]=max(res[u], j); 29 30 if(j*j!=k){ 31 int t=k/j; 32 mp[t]++; 33 if(mp[t]>=depth-1) res[u]=max(res[u], t); 34 } 35 } 36 } 37 38 dfs(u, depth+1); 39 40 for(int j=1;j*j<=k;j++){ 41 if(k%j==0){ 42 mp[j]--; 43 if(j*j!=k) mp[k/j]--; 44 } 45 } 46 } 47 } 48 return; 49 } 50 int main() 51 { 52 int n; 53 54 memset(vis, 0, sizeof(vis)); 55 scanf("%d", &n); 56 for(int i=1;i<=n;i++) scanf("%d", &num[i]); 57 int a,b; 58 for(int i=0;i<n-1;i++){ 59 scanf("%d %d", &a, &b); 60 edge[a].push_back(b); 61 edge[b].push_back(a); 62 } 63 vis[1]=1; 64 res[1]=num[1]; 65 g[1]=num[1]; 66 memset(mp, 0, sizeof(mp)); 67 for(int j=1;j*j<=num[1];j++){ 68 if(num[1]%j==0){ 69 mp[j]++; 70 if(j*j!=num[1]) 71 mp[num[1]/j]++; 72 } 73 } 74 dfs(1, 2); 75 printf("%d", res[1]); 76 for(int i=2;i<=n;i++) 77 printf(" %d", res[i]); 78 printf(" "); 79 }
这个题目有毒,dfs(u, depth+1)后面如果记录了因子再去进行减的操作会wa,重新枚举因子就过了。是不是我姿势不对?