作为一只明媚的兔子,要会叠被子,又得会打蚊子……
兔子住在兔子洞里。兔子洞可以看成是一棵无根树,有
因为蚊子人多势众,所以它们分兵
又一次满脸是包地醒来后,兔子忍无可忍了,于是它找到 lrd,让 lrd 去打蚊子……lrd 不知所措,于是去某宝搞了一个灭蚊器……这个灭蚊器被放在
遗憾的是,兔子洞尚未通电,兔子只能用爱发电。 因此,每个时刻灭蚊器只有
灭蚊器无法影响出现之前和消失之后的蚊子。但在蚊子出现在起点和消失在终点的 那个时刻,如果灭蚊器正常工作且蚊子在作用范围内,这只蚊子仍会被杀死。
兔子对 lrd 的诚意表示怀疑……于是它让 lrd 算出灭蚊器在一晚上期望能杀死多少蚊子。lrd 当然会算了,但是他想考考你。因为兔子讨厌小数,你需要输出这个期望值模
第一行一个整数
一行一个整数,你的答案。
xxxxxxxxxx31 21 31 1 2
xxxxxxxxxx750000007
| 编号 | 分值 | 特殊性质 |
|---|---|---|
| 无 |
对于所有测试点:
本文参考了 这篇题解 的思路,有不少补充。本文的代码与那篇题解的代码有不少相似之处,有不少细节改动。
树形 DP 以及树上路径的好题。这个题目的部分分很有帮助价值。
先考虑
相当于,把根作为 LCA 折点,对于每一棵子树,都贡献了这棵子树叶子个数与非这棵子树叶子个数的乘积,相当于乘法原理的匹配。至于蚊子双向活动的问题,
再考虑满分做法。记录动态规划数组
以
还有一些细节。比如,题目中的分数取模,相当于乘上分母的逆元。灭蚊器消杀概率为
可以全开 long long。
x// mosquitousing namespace std;
int f[SIZE]={0}, dep[SIZE]={0}, cnt[SIZE]={0};vector<int> a[SIZE]; int n, d;int inv;const int mod=1e9+7;
int val(int a, int b){ if(b==0) return 1%mod; a%=mod; int t=val(a, b/2); if(b%2==0) return t*t%mod; return t*t%mod*a%mod;}
void dfs(int u, int fa){ dep[u]=dep[fa]+1; bool leaf=1; for(int v:a[u]) { if(v==fa) continue; leaf=0; dfs(v, u); cnt[u]+=cnt[v]; if(dep[u]<=d+1) f[u]=(f[u]+f[v]*inv%mod)%mod; else f[u]=(f[u]+f[v])%mod; } if(leaf) { cnt[u]=1; if(dep[u]<=d+1) f[u]=inv; else f[u]=1; }}
int ans=0;void calc(int u, int fa) { if(dep[u]>d+1) return; int sum=0, tot=0; for(int v:a[u]) { if(v==fa) continue; sum=(sum+f[v])%mod; tot=(tot+cnt[v])%mod; } for(int v:a[u]) { if(v==fa) continue; ans=(ans+cnt[v]*(tot-cnt[v]+mod)%mod-(sum-f[v]+mod)*f[v]%mod*inv%mod+mod)%mod; calc(v, u); }}
signed main(){ freopen("mosquito.in", "r", stdin); freopen("mosquito.out", "w", stdout); scanf("%lld", &n); for(int i=1; i<n; i++) { int u, v; scanf("%lld %lld", &u, &v); a[u].push_back(v); a[v].push_back(u); } int p, q; scanf("%lld %lld %lld", &d, &p, &q); inv=(q-p)*val(q, mod-2)%mod; dfs(1, 0); calc(1, 0); printf("%lld", ans);
return 0;}All Rights Reserved 2022 Wang Zhanrui