【2020.11.25提高组模拟】树的解构(deconstruct) 题解
【2020.11.25提高组模拟】树的解构(deconstruct) 题解
题目描述
给一棵以\(1\)为根的外向树,进行\((n-1)\)次删边操作,每次都会从没有删掉的边中等概率地删掉一条边\(a\to b\),代价是\(b\)的子树大小。删去这条边后\(b\)为根的子树会形成一棵新的以\(b\)为根的有根外向树。求进行\(n-1\)次操作后期望的代价总和是多少,对\(10^9+7\)取模。
\(n\le2\times10^6\)。
Solution
题解中有两个解决方案,我暂且只看懂了\(\texttt{Alternative Solution}\),就先记录这种吧。
对每个点x考虑计算贡献。当\(x\)会对除了\(x\)自身外的\(x\)的祖先\(y\)产生贡献\(1\)的情况当且仅当\(y\to x\)方向上的\(path_{y\to son_y}\)在\(path_{x\to y}\)内所有边中第一个删去,而这种情况的概率为\(\frac1{dis_{x\to y}}\)。每个\(x\)都有\(dep_x-1\)个这样的祖先\(y\),\(dis_{x\to y}\in [1,dep_x]\cup\mathbb{Z}\),所以点\(x\)的贡献就是
\]
所以
\]
线性(或加个\(\log\)也行)预处理出\(\frac1j\)的前缀,然后\(O(n)\)算\(dep\)即可。
注意别用\(dfs\),会爆栈\(RE\)。
Code
直接放线性求逆元好了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
using namespace std;
template<class T>inline void read(T&x)
{
char ch=getchar();
int fu;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
x*=fu;
}
inline LL read()
{
LL x=0,fu=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do{G[++g]=x%10;x/=10;}while(x);
for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
int n;
int head[2000010],ver[2000010],nxt[2000010];
int cnt;
int depth[2000010],fa[2000010];
void insert(int x,int y)
{
nxt[++cnt]=head[x];
ver[cnt]=y;
head[x]=cnt;
}
void dfs(int x)
{
for(int i=head[x];i;i=nxt[i])
{
dfs(ver[i]);
depth[ver[i]]=depth[x]+1;
}
}
void bfs()//出题人不讲武德 dfs怎么了? 惹你了? (doge)
{
queue<int>q;
q.push(1);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=nxt[i]) q.push(ver[i]),depth[ver[i]]=depth[x]+1;
}
}
#define p 1000000007
LL inv[2000010],sum[2000010];
IL LL qpow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
LL ans;
int main()
{
// freopen("deconstruct.in","r",stdin);
// freopen("deconstruct.out","w",stdout);
n=read();
// for(re int i=1;i<=n;i++) sum[i]=(qpow(i,p-2)+sum[i-1])%p;
inv[0]=inv[1]=sum[1]=1;
for(re int i=2;i<=n;i++)
{
inv[i]=(p-p/i)*inv[p%i]%p;
sum[i]=sum[i-1]+inv[i];
}
for(re int i=2;i<=n;i++) insert(fa[i]=read(),i);
bfs();
for(re int i=1;i<=n;i++) ans=(ans+sum[depth[i]])%p;
write(ans);
return 0;
}
Upd
发生了一件玄学的事情。
\(O(n)\):




\(O(n\log n)\):



两份代码都在上面,\(O(n\log n)\)就是上面的注释部分。
玄学!
Upd-2
现在都过不去了\(\dots\)
展示一份过了的代码吧,但是不保证过。\(jz\)的评测机有点累了啊……
#include<cstdio>
#define mod 1000000007
using namespace std;
int n,dep[2000010],to[2000010],nxt[2000010];
long long ans,kpl[2000010]={0,1},q[2000010]={0,1};
int cnt,h[2000010];
int l=1,r=2;
int res;
char ch;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int read() {
res=0;
ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
return res;
}
inline void add(int x,int y)
{
to[++cnt]=y;
nxt[cnt]=h[x];
h[x]=cnt;
}
int i,x;
int main()
{
freopen("deconstruct.in","r",stdin);
freopen("deconstruct.out","w",stdout);
n=read();
for(i=2;i<=n;i++)
{
add(read(),i);
kpl[i]=kpl[mod%i]*(mod-mod/i);
if(kpl[i]>=mod) kpl[i]%=mod;
}
for(i=2;i<=n;i++)
{
kpl[i]+=kpl[i-1];
if(kpl[i]>=mod) kpl[i]-=mod;
}
while(r-l)
{
x=q[l++];
for(i=h[x];i;i=nxt[i])
{
dep[to[i]]=dep[x]+1;
q[r++]=to[i];
}
}
for(i=1;i<=n;i++)
{
ans+=kpl[dep[i]];
}
printf("%lld",ans%mod);
return 0;
}

【2020.11.25提高组模拟】树的解构(deconstruct) 题解的更多相关文章
- 【2020.11.28提高组模拟】T1染色(color)
[2020.11.28提高组模拟]T1染色(color) 题目 题目描述 给定 \(n\),你现在需要给整数 \(1\) 到 \(n\) 进行染色,使得对于所有的 \(1\leq i<j\leq ...
- 【2020.11.28提高组模拟】T2 序列(array)
序列(array) 题目描述 给定一个长为 \(m\) 的序列 \(a\). 有一个长为 \(m\) 的序列 \(b\),需满足 \(0\leq b_i \leq n\),\(\sum_{i=1}^ ...
- 【2020.11.30提高组模拟】剪辣椒(chilli)
剪辣椒(chilli) 题目描述 在花园里劳累了一上午之后,你决定用自己种的干辣椒奖励自己. 你有n个辣椒,这些辣椒用n-1条绳子连接在一起,任意两个辣椒通过用若干个绳子相连,即形成一棵树. 你决定分 ...
- 【2020.11.30提高组模拟】删边(delete)
删边(delete) 题目 题目描述 给你一棵n个结点的树,每个结点有一个权值,删除一条边的费用为该边连接的两个子树中结点权值最大值之和.现要删除树中的所有边,删除边的顺序可以任意设定,请计算出所有方 ...
- JZOJ 【2020.11.30提高组模拟】剪辣椒(chilli)
题目大意 给出一棵 \(n\) 个节点的树,删去其中两条边 使得分出的三个子树大小中最大与最小的差最小 分析 先一边 \(dfs\) 预处理出以 \(1\) 为根每个点的 \(size\) 然后按 \ ...
- JZOJ 6904. 【2020.11.28提高组模拟】T3 树上询问(query)
题目 你有一棵 \(n\) 节点的树 ,回答 \(m\) 个询问,每次询问给你两个整数 \(l,r\) ,问存在多少个整数 \(k\) 使得从 \(l\) 沿着 \(l \to r\) 的简单路径走 ...
- 11.5NOIP2018提高组模拟题
书信(letter) Description 有 n 个小朋友, 编号为 1 到 n, 他们每人写了一封信, 放到了一个信箱里, 接下来每个人从中抽取一封书信. 显然, 这样一共有 n!种拿到书信的情 ...
- 【2020.12.03提高组模拟】A组反思
估计:40+10+0+0=50 实际:40+10+0+0=50 rank40 T1 赛时看到\(n,m\leq9\),我当机立断决定打表,暴力打了几个点之后发现在\(n\ne m\)且\(k\ne0\ ...
- 【2020.12.01提高组模拟】A组反思
105,rk45 T1 赛时一开始先打了\(m=0\)的情况,也就是普通的卡特兰数,然后打了暴力,样例过了,把样例改改就不行了,原因没有保证是枚举的是合法的出栈序列 得分:\(WA\&TLE1 ...
- 【2020.12.02提高组模拟】A组反思
55,rk47 T1 赛时先想了\(trie\),想到不一定是前缀,然后就放弃转为打暴力 得分:\(RE22\) 正解是只用判断\(i\)与\(i+1\)的关系,那么只有两种情况,判断一下然后\(dp ...
随机推荐
- 【Matlab函数】提取inp文件中的节点、单元数据并保留集合信息
功能 提取hypermesh2020(其他版本也可以)中的节点.单元信息,并保留elem set信息. 返回的是一个结构体 输入输出参数 输入: inp文件路径,如:'example.inp'.&qu ...
- 【ABAQUS后处理】打印视口到文件
abaqus cae 允许您在画布上打印一个或多个视口的快照,并将图像直接发送到打印机或文件以供以后使用,例如包含在嵌入打印报告的演示文稿中或以 html 格式显示document 打印的图像将在画布 ...
- VitePress全局组件封装
前言 VuePress 主题默认有 <CodeGroup> 组件用于切换代码很方便. 如图所示: 痛点 使用 VitePress 后,官方没有提供 <CodeGroup> 组件 ...
- PHP的回调函数
所谓的回调函数,就是指调用函数时并不是向函数中传递一个标准的变量作为参数,而是将另一个函数作为参数传递到调用的函数中,这个作为参数的函数就是回调函数.通俗的来说,回调函数也是一个我们定义的函数,但是不 ...
- oracle中的aix,Oracle在AIX上一些处理
一.Oracle在aix上连接 1.su - oracle //进入oracle用户: 2.export ORACLE_SID=house //指定实例,多个实例的情况下: 3.sqlplus / ...
- elementui|dropdown|下拉菜单作为模态框使用
elementui|dropdown|下拉菜单作为模态框使用 背景 场景:下拉菜单作为模态框使用: 操作:下拉菜单设置触发条件点击展示/隐藏:trigger="click" 目的: ...
- 系统自带模版在 emlog pro 1.8.0 底部信息错位问题暂时的解决方案
问题描述 作为一名 emlog 爱好者,笔者闲暇时间经常为 emlog 系统的 Github 仓库里( https://github.com/emlog/emlog )提 pr 和修修补补,就像其他知 ...
- LLM应用落地实施手册
背景 自ChatGPT诞生以来,各个企业都开始尝试引入LLM落地实施"智能"应用,而目前并没有太多文章系统地介绍应该怎么落地实施一个基于LLM的应用,到底应该做哪些步骤.本人从20 ...
- 无耳 Solon Ai MCP,发布工具服务,使用工具服务。效果预览!
solon-ai-mcp 是 solon-ai 的扩展特性.提供 mcp 协议的支持.通过它,可以方便的发布 Tool Service,方便的使用 Tool Service. 引入依赖包 <de ...
- jmeter从文档CSV内读取参数且文件路径为相对路径
如下图,"全站链接扫描"脚本的参数化文件存储在同一目录的参数化文件夹内 预计实现读取该文件使用相对路径(非绝对路径,避免脚本在另一台电脑存在别的目录下能正常读取参数文件) 如读取& ...