最小生成树
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 }