题目大意

  有两棵 \(n\) 个点的树 \(T_1\) 和 \(T_2\)。

  你要给每个点一个权值吗,要求每个点的权值为 \([1,y]\) 内的整数。

  对于一条同时出现在两棵树上的边,这条边的两个端点的值相同。

  若 \(op=0\),则给你两棵树 \(T_1,T_2\),求方案数。

  若 \(op=1\),则给你一棵树 \(T_1\),求对于所有 \(n^{n-2}\) 种 \(T_2\),方案数之和。

  若 \(op=2\),则求对于所有的 \(T_1,T_2\),求方案数之和。

  \(n\leq 100000\)

题解

  新建一个图 \(G\),把两棵树的公共边加到 \(G\) 中。记 \(m\) 为两棵树的公共边数量。那么答案就是 \(y^{n-m}\)。

  令 \(z=y^{-1}\),那么答案就变成了 \(y^nz^m\)。也就是说,每有一条相同的边,方案的贡献就要 \(\times z\)。

op=0

  这个大家都会。

op=1

\[z^m=\sum_{i=0}^m\binom{m}{i}(z-1)^i
\]

  那么可以枚举一个边集 \(E\),计算有多少种生成树包含 \(E\),然后把答案加上方案数 \(\times{(z-1)}^{\lvert E\rvert}\)。

  记这 \(E\) 条边形成了 \(m\) 个连通块,这些连通块的大小为 \(a_1,a_2,\ldots,a_m\),那么贡献就是

\[\begin{align}
&{(z-1)}^{n-m}\sum_{\sum_{i=1}^md_i=2m-2}(m-2)!\prod_{i=1}^m\frac{a_i^{d_i}}{(d_i-1)!}\\
=&{(z-1)}^{n-m}n^{m-2}\prod_{i=1}^ma_i\\
\end{align}
\]

  \(\prod_{i=1}^ma_i\) 可以看成是每个连通块内选一个点的方案数。这样就可以DP了。

  时间复杂度:\(O(n)\)

op=2

  枚举两棵树的公共边个数:

\[\begin{align}
s_n&=\sum_{i=1}^{n}{(z-1)}^{n-i}\sum_{\sum_{j=1}^ia_j=n}\frac{n!}{i!}(\prod_{j=1}^i\frac{a_j^{a_j-2}}{a_j!})(n^{i-2}\prod_{j=1}^ia_j)^2\\
&=\sum_{i=1}^{n}{(z-1)}^{n-i}\frac{n!n^{2i-4}}{i!}\sum_{\sum_{j=1}^ia_j=n}\prod_{j=1}^i\frac{a_j^{a_j}}{a_j!}\\
&=\sum_{i=1}^{n}{(z-1)}^{n-i}n^{2i-4}\sum_{\sum_{j=1}^ia_j=n}\prod_{j=1}^i\binom{(\sum_{k=1}^ja_k)-1}{a_j-1}{}a_j^{a_j}\\
\end{align}
\]

  记 \(f_l=\sum_{i=1}^{l}{(z-1)}^{-i}n^{2i}\sum_{\sum_{j=1}^ia_j=l}\prod_{j=1}^i\binom{(\sum_{k=1}^ja_k)-1}{a_j-1}{}a_j^{a_j}\)。

  转移时枚举最后一块的大小,有:

\[f_i=\begin{cases}
1&,i=0\\
\sum_{j=1}^i\frac{(i-1)!n^2j^jf_{i-j}}{(i-j)!(j-1)!(z-1)}&,i>0
\end{cases}
\]

  直接DP是 \(O(n^2)\) 的。

  记 \(g_i=\sum_{i\geq 1}\frac{n^2i^i}{(i-1)!(z-1)}\),\(F(x)\) 为 \(f\) 的 EGF,\(G(x)\) 为 \(g\) 的 OGF,那么

\[\begin{align}
xF'(x)&=F(x)G(x)\\
\frac{F'(x)}{F(x)}&=\frac{G(x)}{x}\\
\ln F(x)&=\int \frac{G(x)}{x}\\
F(x)&=e^{\int \frac{G(x)}{x}}
\end{align}
\]

  直接多项式 exp 就好了。

  答案为 \((z-1)^nn^{-4}f_n\)

  时间复杂度:\(O(n\log n)\)

代码

const ll p=998244353;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
const int N=100010;
int n,op;
ll z,_z;
ll ans;
namespace solve0
{
map<int,int> a[N];
void solve()
{
if(_z==1)
{
ans=1;
return;
}
int x,y;
for(int i=1;i<n;i++)
{
io::get(x);
io::get(y);
if(x>y)
swap(x,y);
a[x][y]++;
}
ans=1;
for(int i=1;i<n;i++)
{
io::get(x);
io::get(y);
if(x>y)
swap(x,y);
if(a[x].count(y))
ans=ans*z%p;
}
}
}
namespace solve1
{
vector<int> g[N];
ll f[N][2];
void dfs(int x,int fa)
{
f[x][0]=f[x][1]=1;
for(auto v:g[x])
if(v!=fa)
{
dfs(v,x);
ll s0=(f[x][0]*f[v][0]%p*z+f[x][0]*f[v][1]%p*n)%p;
ll s1=(f[x][0]*f[v][1]%p*z+f[x][1]*f[v][0]%p*z+f[x][1]*f[v][1]%p*n)%p;
f[x][0]=s0;
f[x][1]=s1;
}
}
void solve()
{
if(_z==1)
{
ans=fp(n,n-2);
return;
}
int x,y;
for(int i=1;i<n;i++)
{
io::get(x);
io::get(y);
g[x].push_back(y);
g[y].push_back(x);
}
z--;
dfs(1,0);
ans=f[1][1]*fp(n,p-2)%p;
}
}
namespace solve2
{
const int N=270000;
namespace ntt
{
const int W=262144;
ll w[N];
int rev[N];
void init()
{
w[0]=1;
ll s=fp(3,(p-1)/W);
for(int i=1;i<W/2;i++)
w[i]=w[i-1]*s%p;
}
void ntt(ll *a,int n,int t)
{
for(int i=1;i<n;i++)
{
rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
if(rev[i]>i)
swap(a[i],a[rev[i]]);
}
for(int i=2;i<=n;i<<=1)
for(int j=0;j<n;j+=i)
for(int k=0;k<i/2;k++)
{
ll u=a[j+k];
ll v=a[j+k+i/2]*w[W/i*k];
a[j+k]=(u+v)%p;
a[j+k+i/2]=(u-v)%p;
}
if(t==-1)
{
reverse(a+1,a+n);
ll inv=fp(n,p-2);
for(int i=0;i<n;i++)
a[i]=a[i]*inv%p;
}
}
void mul(ll *a,ll *b,ll *c,int n,int m,int l)
{
static ll a1[N],a2[N];
int k=1;
while(k<=n+m)
k<<=1;
memset(a1,0,sizeof(a1[0])*k);
memset(a2,0,sizeof(a2[0])*k);
memcpy(a1,a,sizeof(a1[0])*(n+1));
memcpy(a2,b,sizeof(a2[0])*(m+1));
ntt::ntt(a1,k,1);
ntt::ntt(a2,k,1);
for(int i=0;i<k;i++)
a1[i]=a1[i]*a2[i]%p;
ntt::ntt(a1,k,-1);
memcpy(c,a1,sizeof(a1[0])*(l+1));
}
void inv(ll *a,ll *b,int n)
{
if(n==1)
{
b[0]=fp(a[0],p-2);
return;
}
inv(a,b,n>>1);
static ll a1[N],a2[N];
memset(a1,0,sizeof(a1[0])*(n<<1));
memset(a2,0,sizeof(a2[0])*(n<<1));
memcpy(a1,a,sizeof(a1[0])*n);
memcpy(a2,b,sizeof(a2[0])*(n>>1));
ntt(a1,n<<1,1);
ntt(a2,n<<1,1);
for(int i=0;i<n<<1;i++)
a1[i]=a2[i]*(2-a1[i]*a2[i]%p)%p;
ntt(a1,n<<1,-1);
memcpy(b,a1,sizeof(a1[0])*n);
}
void ln(ll *a,ll *b,int n)
{
static ll a1[N],a2[N],a3[N];
for(int i=1;i<n;i++)
a1[i-1]=a[i]*i%p;
a1[n-1]=0;
inv(a,a2,n);
mul(a1,a2,a3,n-1,n-1,n-1);
for(int i=1;i<n;i++)
b[i]=a3[i-1]*fp(i,p-2)%p;
b[0]=0;
}
void exp(ll *a,ll *b,int n)
{
if(n==1)
{
b[0]=1;
return;
}
exp(a,b,n>>1);
static ll a1[N],a2[N],a3[N];
memset(b+(n>>1),0,sizeof(b[0])*(n>>1));
ln(b,a3,n);
memset(a1,0,sizeof(a1[0])*n);
memset(a2,0,sizeof(a2[0])*n);
memcpy(a1,b,sizeof(a1[0])*(n>>1));
for(int i=0;i<(n>>1);i++)
a2[i]=a[(n>>1)+i]-a3[(n>>1)+i];
ntt(a1,n,1);
ntt(a2,n,1);
for(int i=0;i<n;i++)
a1[i]=a1[i]*a2[i]%p;
ntt(a1,n,-1);
memcpy(b+(n>>1),a1,sizeof(a1[0])*(n>>1));
}
}
ll inv[N],fac[N],ifac[N];
ll f[N],g[N],w[N];
void solve()
{
if(_z==1)
{
ans=fp(n,n-2)*fp(n,n-2)%p;
return;
}
z--;
ntt::init();
fac[0]=fac[1]=ifac[0]=ifac[1]=inv[1]=1;
for(int i=2;i<=n;i++)
{
fac[i]=fac[i-1]*i%p;
inv[i]=-p/i*inv[p%i]%p;
ifac[i]=ifac[i-1]*inv[i]%p;
}
ll ifacz=fp(z,p-2); // f[0]=1;
// for(int i=1;i<=n;i++)
// w[i]=fp(i,i);
// for(int i=1;i<=n;i++)
// for(int j=1;j<=i;j++)
// f[i]=(f[i]+f[i-j]*fac[i-1]%p*ifac[i-j]%p*ifac[j-1]%p*n%p*n%p*w[j]%p*ifacz)%p; for(int i=1;i<=n;i++)
g[i]=fp(i,i)*n%p*n%p*ifac[i-1]%p*ifacz%p*inv[i]%p;
int k=1;
while(k<=n)
k<<=1;
ntt::exp(g,f,k);
ans=f[n]*fac[n]%p*fp(z,n)%p*fp(n,p-1-4)%p;
}
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
io::get(n);
io::get(_z);
io::get(op);
z=fp(_z,p-2);
if(op==0)
solve0::solve();
else if(op==1)
solve1::solve();
else
solve2::solve();
ans=ans*fp(_z,n)%p;
ans=(ans%p+p)%p;
io::put(ans);
return 0;
}

【WC2019】数树 树形DP 多项式exp的更多相关文章

  1. BZOJ5475 WC2019数树(prufer+容斥原理+树形dp+多项式exp)

    因为一大堆式子实在懒得写题解了.首先用prufer推出CF917D用到的结论,然后具体见前言不搭后语的注释. #include<iostream> #include<cstdio&g ...

  2. [WC2019] 数树

    [WC2019] 数树 Zhang_RQ题解(本篇仅概述) 前言 有进步,只做了半天.... 一道具有极强综合性的数数好题! 强大的多合一题目 精确地数学推导和耐心. 有套路又不失心意. 融合了: 算 ...

  3. 洛谷 P5206: bzoj 5475: LOJ 2983: [WC2019] 数树

    一道技巧性非常强的计数题,历年WC出得最好(同时可能是比较简单)的题目之一. 题目传送门:洛谷P5206. 题意简述: 给定 \(n, y\). 一张图有 \(|V| = n\) 个点.对于两棵树 \ ...

  4. 【BZOJ-3572】世界树 虚树 + 树形DP

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 611[Submit][Status ...

  5. 51nod 1353 树 | 树形DP经典题!

    51nod 1353 树 | 树形DP好题! 题面 切断一棵树的任意条边,这棵树会变成一棵森林. 现要求森林中每棵树的节点个数不小于k,求有多少种切法. 数据范围:\(n \le 2000\). 题解 ...

  6. bzoj 2286(虚树+树形dp) 虚树模板

    树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5002  Sol ...

  7. 【BZOJ-2286】消耗战 虚树 + 树形DP

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status] ...

  8. 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...

  9. BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca

    BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...

随机推荐

  1. ASP.Net Mvc实现自定义User Identity用户身份识别系统(2)

    上一篇博文中已经实现了如何在页面上使用自定义的属性即上篇博文所示的@this.U,今天将进一步研究用户自定义User Identity; 实现思路: 通过研究微软自带identity的套路,我们可以发 ...

  2. Vue 单选框与单选框组 组件

    radio组件 v-model  : 通过当然绑定的值与input上的value值来确定当前选中项. 在父作用域中通过active设置当前默认选中项,如果选中项发生改变后通过input事件通知传递到父 ...

  3. Android为TV端助力 listview与recyclerview上下联动

    首先是主布局fragment里面的xml文件 <?xml version="1.0" encoding="utf-8"?><RelativeL ...

  4. C#零基础入门-2-Visual Studio (VS)程序初始化及各组成部分

    X:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe 可以使用桌面快捷方式启动,也可以从开始菜单启动,还 ...

  5. java获取机器IP地址常用方法

    private String getHostIP(){ Enumeration<NetworkInterface> allNetInterfaces = null; String resu ...

  6. C#图片添加文字水印

    /// <summary> /// 给图片添加文字水印 /// </summary> /// <param name="img">图片</ ...

  7. mysql 基础sql语句

    1.mysqladmin语句:  # 查看mysql版本 mysqladmin version  # 更改root用户密码 mysqladmin -u root -p原密码 password '新密码 ...

  8. LeetCode算法题-Largest Number At Least Twice of Others(Java实现)

    这是悦乐书的第308次更新,第328篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第177题(顺位题号是747).在给定的整数数组中,总有一个最大的元素.查找数组中的最大 ...

  9. java网络爬虫基础学习(二)

    正则表达式 正则表达式写法 含义 \d 代表0-9的任意数字 \D 代表任何非数字字符 \s 代表空格类字符 \S 代表非空格类字符 \p{Lower} 代表小写字母[a-z] \p{Upper} 代 ...

  10. 功能测试话题分享-0323 Bug