传送门:牛客
题目描述:
修修去年种下了一棵树,现在它已经有n个结点了。
修修非常擅长数数,他很快就数出了包含每个点的连通点集的数量。
澜澜也想知道答案,但他不会数数,于是他把问题交给了你。
输入:
6
1 2
1 3
2 4
4 5
4 6
输出:
12
15
7
16
9
9
这道题很好的帮我巩固了换根dp+乘法逆元+快速幂的知识,自我感觉是一道很好的题目
主要思路:
在下列中 mod=1e9+7
所以此时我们得想另一个办法来解决除法取模的问题
对于乘法逆元,有一个比较简单的计算方法,使用到了快速幂
和费马小定理
对于费马小定理.我们有 a p − 1 ≡ 1 m o d p a^{p-1}\equiv1\mod p ap−1≡1modp 需要我们的 a ≠ p , p 为 质 数 a\neq p,p为质数 a=p,p为质数
然后对于我们的 a / b % m o d a/b\% mod a/b%mod,我们可以找到一个X满足 b x ≡ 1 % m o d bx\equiv1 \% mod bx≡1%mod
那么此时我们显然有 a / b ∗ b ∗ x ≡ a / b ( % m o d ) a/b*b*x\equiv a/b(\% mod) a/b∗b∗x≡a/b(%mod),然后我们就有 a ∗ x ≡ a / b ( % m o d ) a*x\equiv a/b(\% mod) a∗x≡a/b(%mod)
然后我们只要找出我们的b的逆元X即可.然后我们使用费马小定理,
有 b p − 2 ∗ b ≡ 1 % m o d ) b^{p-2}*b\equiv1\% mod) bp−2∗b≡1%mod),然后我们巧妙的就发现我们的 b p − 2 b^{p-2} bp−2恰好就是我们的乘法逆元,所
以我们直接使用快速幂求解即可
对于这个暴力我们的算法也很简单,就是在之前求解d数组的算法中,加入一个限制不能遍历我们此时的子树v即可
下面是我们的代码部分:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000010
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n;
vector<ll>tree[maxn];
ll d[maxn];ll dp[maxn];
const int mod=1e9+7;
ll qpow(ll a,ll b) {
ll ans=1;
while(b) {
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void dfs1(ll u,ll pre_u) {
d[u]=1;
for(int i=0;i<tree[u].size();i++) {
ll v=tree[u][i];
if(v==pre_u) continue;
dfs1(v,u);
d[u]=d[u]*(d[v]+1)%mod;
}
return ;
}
void dfs2(ll u,ll pre_u) {
for(int i=0;i<tree[u].size();i++) {
int v=tree[u][i];
if(v==pre_u) continue;
ll inv=qpow(d[v]+1,mod-2);
if(inv) {
dp[v]=(inv*dp[u]%mod+1)%mod*d[v]%mod;
}else {
ll ans=1;
for(int j=0;j<tree[u].size();j++) {
int vv=tree[u][j];
if(vv==v||vv==pre_u) continue;
ans=ans*(d[vv]+1)%mod;
}
dp[v]=(d[v]*(ans+1))%mod;
}
dfs2(v,u);
}
return ;
}
int main() {
n=read();int u,v;
for(int i=1;i<=n-1;i++) {
u=read();v=read();
tree[u].push_back(v);
tree[v].push_back(u);
}
dfs1(1,0);
dp[1]=d[1];
dfs2(1,0);
for(int i=1;i<=n;i++) printf("%lld\n",dp[i]);
return 0;
}