WC2019 数树
Task 0
判断有多少条相同边即可。
复杂度\(O(N)\)
namespace Subtask1{
pair<int,int> e1[N],e2[N];
void Main(int n,int y){
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
e1[i] = pair<int,int> (min(u,v), max(u,v));
}
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
e2[i] = pair<int,int> (min(u,v), max(u,v));
}
sort(e1+1,e1+n),sort(e2+1,e2+n);
int j = 1,B = n;
for(int i=1;i<n;i++){
while(j<n&&e2[j]<e1[i])++j;
if(j<n && e2[j] == e1[i]) B--;
}
cout << qpow(y,B) << endl;
}
}
Task 1
考虑prufer序列,如果硬点了一些边一定被重复覆盖,那么硬点这\(c\)个联通块的方案是:
\[n^{c-2} \prod siz_i
\]
考虑系数,硬点了\(a\)条边会在硬点\(b\)条边中出现了\(\binom{a}{b}\)次,恰好\(a\)条边的贡献是\(y^{n-a}\)。
考虑:
\[\sum _i\binom {A}{i} x^i = (x+1)^A
\]
那么系数设置为\(y^{-1}-1\)时,正好会贡献\(y^{-A}\)。
把\(siz\)的贡献拆组合意义,即:每个连通块内都要选一个节点作为代表。
设\(f[x][0/1]\)表示当前节点所在连通块是否选了代表。
复杂度$O(n) $
namespace Subtask2{
int hed[N],to[N<<1],nxt[N<<1],cnt;
inline void adde(int u,int v){++cnt;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;}
int f[N][2],Val;
inline void dfs(int x,int pre){
f[x][1] = n, f[x][0] = 1;
for(int i=hed[x];i;i=nxt[i]){
int v=to[i];if(v==pre)continue;
dfs(v,x);int f1=0,f0=0;
f1 = add(mul(f[x][1], add(mul(Val,f[v][0]),f[v][1])), mul(mul(Val, f[x][0]), f[v][1]));
f0 = mul(f[x][0], add(mul(Val, f[v][0]),f[v][1]));
f[x][1] = f1, f[x][0] = f0;
}
}
void Main(int n,int y){
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
adde(u,v),adde(v,u);
}Val = sub(qpow(y,mod-2),1);
dfs(1,0);
// cout << mul(f[1][1], qpow(9,mod-2)) << endl;
printf("%d\n",mul(qpow(1ll*n*n%mod,mod-2),mul(qpow(y,n), f[1][1])));
}
}
Task 2
容斥系数和以上一样,\(f[i]\)表示\(i\)个点的连通块的贡献。现在要枚举的树是两颗树,所以方案的贡献要平方。
写成\(EGF\)之后\(exp\)就行了。
\(O(n\log n)\)
namespace Subtask3{
using namespace Template_Poly;
Poly f;
int ifac[N], fac[N], Val;
inline void init(int n = 1e5){
fac[0] = ifac[0] = 1;for(int i=1;i<=n;i++)fac[i] = mul(fac[i-1], i);
ifac[n] = qpow(fac[n], mod-2);for(int i=n-1;i;i--)ifac[i] = mul(ifac[i+1], i+1);
}
inline void initf(int n){
f.resize(n+1);
for(int i=1,w = 1;i<=n;i++, w = mul(w, Val)){
f[i] = w;f[i] = mul(f[i], mul(qpow(i,max(0,i-2)), 1ll*n*n%mod));
f[i] = mul(f[i], 1ll*i*i%mod);
f[i] = mul(f[i], ifac[i]);
}
}
void Main(int n,int y){
Val = sub(qpow(y,mod-2),1);
init();initf(n);
f = exp(f);
int ans = mul(f[n],fac[n]);
ans = mul(ans, qpow(1ll*n*n%mod*n%mod*n%mod,mod-2));
ans = mul(ans, qpow(y,n));
cout << ans << endl;
}
}