当前位置:
首页 >
CF1540B-Tree Array【数学期望,dp】
发布时间:2023/12/3
45
豆豆
生活随笔
收集整理的这篇文章主要介绍了
CF1540B-Tree Array【数学期望,dp】
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
正题
题目链接:https://www.luogu.com.cn/problem/CF1540B
题目大意
nnn个点的一棵树,开始随机选择一个点标记,然后每次随机选择一个与被标记点连边的点标记,按照标记顺序排列,求期望逆序对数。
1≤n≤2001\leq n\leq 2001≤n≤200
解题思路
显然是考虑两个点(x,y)(x,y)(x,y)产生的贡献。
枚举根,然后两个点到根路径上公共的部分没有用,考虑不公共的部分一个长度为nnn,另一个长度为mmm,假设nnn先标记,此时我们可以枚举nnn标记的时候mmm还有多少个没标记的,概率就是
12∑i=0m−1(n−1+ii)12n−1+i\frac{1}{2}\sum_{i=0}^{m-1}\binom{n-1+i}{i}\frac{1}{2}^{n-1+i}21i=0∑m−1(in−1+i)21n−1+i
这个显然可以用dpdpdp进行O(n2)O(n^2)O(n2)预处理。
然后在LCALCALCA处暴力枚举点对就好了,时间复杂度:O(n3)O(n^3)O(n3)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=210,P=1e9+7; struct node{ll to,next; }a[N<<1]; ll n,tot,cnt,f[N][N],ls[N],v[N],dep[N],inv[N],ans; void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void calc(ll x,ll fa,ll fr,ll L){v[++cnt]=x;ans+=x<fr;for(ll i=1;i<=L;i++){int n=dep[x]-dep[fr];int m=dep[v[i]]-dep[fr];if(v[i]>x)swap(n,m);(ans+=f[n-1][m-1]*inv[2]%P)%=P;}for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;calc(y,x,fr,L);}return; } void solve(ll x,ll fa){dep[x]=dep[fa]+1;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;solve(y,x);}cnt=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;calc(y,x,x,cnt);}return; } signed main() {scanf("%lld",&n);inv[1]=1;for(ll i=2;i<=n;i++)inv[i]=P-inv[P%i]*(P/i)%P;f[0][0]=1;for(ll i=0;i<=n;i++)for(ll j=0;j<=n;j++){if(!i&&!j)continue;f[i][j]=((i?f[i-1][j]:0)+(j?f[i][j-1]:0))*inv[2]%P;}for(ll i=0;i<=n;i++)for(ll j=1;j<=n;j++)(f[i][j]+=f[i][j-1])%=P; for(ll i=1,x,y;i<n;i++){scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}for(ll i=1;i<=n;i++)solve(i,0);printf("%lld\n",ans*inv[n]%P);return 0; }总结
以上是生活随笔为你收集整理的CF1540B-Tree Array【数学期望,dp】的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: P5311-[Ynoi2011]成都七中
- 下一篇: P7887-「MCOI-06」Exist