题目大意:
如图所示
题目思路:
首先考虑 前n个点,可以组成的最小生成树的权值是多少 那么必然是(n-1)
原因:x 一定与 x-1 互质
那么就可以用dp[i] 表示前i个点构成的最小生成树的方案数,现在考虑放入第i+1个点,为了保证最小生成树的权值,此时一定会去连接 与i+1互质的点
所以状态很显然:
dp[i] = dp[i-1]*oula[i]
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 2e5+700;
const ll mod= 1e8+7;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll oula[maxn],prime[maxn],vis[maxn];
int cnt = 0;
ll dp[maxn];
void set_prime(){
for(int i=1;i<maxn;i++)
vis[i]=(i==1?false:true);//假设除了1以外都是素数
for(int i=2;i<maxn;i++)
{
if(vis[i]) prime[++cnt]=i,oula[i]=i-1;
for(int j=1;j<=cnt&&i*prime[j]<maxn;j++){
vis[i*prime[j]]=false;
if(i%prime[j]==0){
oula[i*prime[j]]=oula[i]*prime[j];//当他们不互质时,有共同因子
break;
}
oula[i*prime[j]]=oula[i]*oula[prime[j]];//互质时积性函数分解
}
}
}
int main(){
set_prime();
dp[1] = 1;
read(n);
for(int i=2;i<=n;i++) dp[i] = (dp[i-1]*oula[i])%mod;
printf("%lld\n",dp[n]);
return 0;
}