最小生成树

P2427 - 最小生成树

Description

话说正在 jmy 愁苦如何筹钱给大家买汽水的时候,他遇上了一位魔法师。魔法师希望 jmy能帮他破解魔法书的咒语。如果 jmy 做到了,就帮他付所有买汽水的钱。
魔法书上画了一个完全图(每两个点之间有且只有一条边),每个点都有一个独一无二的[1,n]内的编号,jmy 的任务是要找到最小生成树,以此作为魔法树,从而破解咒语。
对于完全图的边(i,j) (i≠j)的边权恰好就等于 i,j 两个数字的最大公约数。
特别地,要作为魔法树,必须满足树指定某个点为根后,所有除根以外的节点的父亲的标号必须小于自身标号。
jmy 一眼就看出了最小生成树的边权和。然而咒语却是最小生成树的个数。 为了保证大家都有汽水喝,你能帮帮 jmy 吗?

Input

一行仅一个数 N,表示完全图的大小。

Output

一行一个整数,表示答案对 100,000,007 取模(mod)的结果。

Sample Input

3

Sample Output

2

Hint

【数据规模】
对于 10%的数据,N≤5;
对于 30%的数据,N≤8;
对于 40%的数据,N≤10;
对于 70%的数据,N≤5,000;
对于 100%的数据,N≤20,000。

 

 

手玩可以发现,要求的就是欧拉函数的第2到n项的积。
简略证(xia)明(che):
首先最小生成数的权值和肯定是n-1,这个很显然。
然后要满足题目说的,每个点的父亲只能是比他小的点,而且边权要唯一,
那么只能连接和它互质的数,然后就是乘法原理啊。

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 #define maxn 20010
15 #define mod 100000007
16 using namespace std;
17 int bj[maxn],su[maxn],phi[maxn];
18 int main()
19 {
20   freopen("!.in","r",stdin);
21   freopen("!.out","w",stdout);
22   int n;
23   scanf("%d",&n);
24   int sum=0;
25   for(int i=2;i<=n;i++){
26     if(!bj[i]) su[++sum]=i,phi[i]=i-1;
27     for(int j=1;j<=sum;j++){
28       if(su[j]*i>n) break;
29       bj[su[j]*i]=1;
30       if(i%su[j]==0){
31     phi[su[j]*i]=phi[i]*su[j];
32     break;
33       }
34       else phi[su[j]*i]=phi[i]*(su[j]-1);
35     }
36   }
37   long long ans=1;
38   for(int i=2;i<=n;i++)
39     ans=(ans*phi[i])%mod;
40   printf("%lld",ans);
41   return 0;
42 }

 

 
posted @ 2017-03-29 22:34  嘘丶  阅读(217)  评论(1编辑  收藏  举报