hihoCoder挑战赛4 光棍节
题目3 : 光棍节
时间限制:30000ms
单点时限:1000ms
内存限制:256MB
描述
尽管付出了种种努力,jzp还是得过光棍节。
jzp非常不爽,但也无能为力,只能够哀叹起来他的命运。他想到了一位长者的人生经验:“人的一生,不光要靠自我奋斗,也要考虑历史的进程”。
他终于明白自己只是时运不济,所以又继续开始努力。终于在圣诞节当天把到了妹子。
jzp从此过上了快乐的现充生活,在圣诞节当天,他还和妹子玩起了有趣的游戏:
jzp的家里有一棵非常大的圣诞树,可以看成是一个n个点的无向联通无环图。每个点上都有一个正整数,JZP和妹子每次都会选择树上的一条路径,
这条路径的权值被定义为路径上所有点上数的最大公约数,JZP可以得到这个权值的分数。
JZP玩了一会儿有点腻了,他想知道对于每种可能的权值x,权值为x的不同路径的数量(a到b的路径和b到a的路径算作一种,a到a自身也算作一条路径。)
输入
第一行一个整数n(1<=n<=105)表示圣诞树的大小,点从1开始标号。
接下来一行n个整数用单个空格隔开,第i个表示第i个点上的数。(数都在1到105之间)。
接下来n-1行,每行两个数a和b,表示a和b之间有一条边。
输出
令C(x)表示权值为x的路径的个数。
从小到大输出对于所有C(x)>0的x,输出一行两个数x和C(x),用空格隔开。
- 样例输入
-
20 2 4 2 4 2 4 2 20 20 12 12 12 2 12 2 4 4 2 12 2 1 2 1 3 1 4 2 5 3 6 1 7 6 8 2 9 6 10 5 11 4 12 11 13 10 14 3 15 9 16 7 17 4 18 4 19 16 20
- 样例输出
-
2 186 4 16 12 6 20 2
思路:一看就是树分治的题,可是想想都会T 啊,可是实在没事可以做,所以只有去暴力了,加了一些优化,
交了wa,改了改,还是wa 。。。。 后面把优化全部去掉,终于T了,好像很兴奋的样子
后面看了代码,发现一个地方错了,可是只有几分钟了。。。。
改了交,然后有把优化加上,又交了一发。
然后结束了,心里想又挂0 了。。。
后面没加优化的过了。。。。。==
最后一分钟过的。。不容易呀#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define ll long long #define INF 0x3f3f3f3f #define maxn 200010 #define eps 1e-6 #define mod 1000000007 using namespace std; int head[maxn] , to[maxn*2] ,next1[maxn*2] ; int top ,cnt[maxn] , f[maxn]; int k ,ans ,n ; vector<int>vec; bool vi[maxn] ; void Unit(int x,int y) { to[top]=y;next1[top]=head[x] ; head[x]=top++; } void find1( int u ,int fa ) { f[u] = 0 ; cnt[u] = 1 ; int v ; for( int i = head[u] ; i != -1; i = next1[i]) { v = to[i] ; if(v==fa||vi[v]) continue ; find1(v,u) ; cnt[u] += cnt[v] ; f[u] = max(cnt[v],f[u]) ; } } int minn ; void find_root1( int u ,int fa,int &root,int sum) { int tmp = max(sum-cnt[u],f[u]) ; if(tmp < minn) { minn = tmp ; root = u ; } int v; for( int i = head[u] ; i != -1; i = next1[i]) { v = to[i] ; if(v==fa||vi[v]) continue ; find_root1(v,u,root,sum) ; } } int get_root( int u ) { find1(u,-1) ; int sum = cnt[u] ; int root = u ; minn = n ; find_root1(u,-1,root,sum) ; return root ; } int ret ,MAX,num[maxn],val[maxn] ; LL c[maxn]; int gcd(int a,int b) { int c; while(b) { c = a%b ; a = b ; b = c ; } return a ; } int num1,num2; vector<int>q; void find(int d) { int x,n=q.size(); for(int i =0 ; i < n ;i++) { x = gcd(q[i],d) ; c[x] += num[q[i]] ; } } void dfs1(int u ,int fa,int root,int d ) { vec.push_back(d); c[d]++; /* if(d==1)c[1] += num1 ; else if(d==2) c[2] += num2 ;*/ find(d) ; int j,v ; for( int i = head[u] ; i != -1 ; i = next1[i]) { v = to[i] ; if(vi[v]||v==fa) continue ; dfs1(v,u,1,gcd(d,val[v])) ; } } int que[maxn],l; void count( int u ) { int j,v ; l=0; num1=num2=0; q.clear(); for( int i = head[u] ; i != -1 ; i = next1[i]) { v = to[i] ; if(vi[v]) continue ; vec.clear() ; dfs1(v,u,-1,gcd(val[u],val[v])); for( j = 0 ; j < vec.size();j++){ if(num[vec[j]]==0)q.push_back(vec[j]); num[vec[j]]++ ; num1++; if(vec[j]&1){} else num2++; que[l++]=vec[j]; } } for( int i = 0 ; i < l ;i++) num[que[i]] = 0; } void solve( int u ) { int root = get_root(u) ; vi[root] = 1 ; count(root) ; int v ; for( int i = head[root] ; i != -1 ; i = next1[i]) { v = to[i] ; if(vi[v]) continue ; solve(v) ; } } int main() { int i , m ,k , j ; int x,y; while(scanf("%d",&n) != EOF) { MAX=0; memset(c,0,sizeof(c)) ; memset(num,0,sizeof(num)); for( i = 1 ; i <= n ;i++){ scanf("%d",&val[i]) ; c[val[i]]++; MAX=max(MAX,val[i]) ; } memset(head,-1,sizeof(head)) ; memset(vi,0,sizeof(vi)); top=0; for(i = 1 ; i < n ;i++) { scanf("%d%d",&x,&y) ; Unit(x,y) ; Unit(y,x) ; } solve(1) ; for( i =1 ; i <= MAX;i++)if(c[i]>0) { cout<<i<<" "<<c[i]<<endl; } } return 0 ; }