P4895 独钓寒江雪
千山鸟飞绝,万径人踪灭。
孤舟蓑笠翁,独钓寒江雪。
题目中本质不同独立集表述不清,实际上含义是若存在两独立集分别在 \(u,v\) 为根,无标号时,树的结构与节点染色情况相同,则记为一种。
要去除换根后相同的情况不好处理。考虑能否去除此限制,貌似是套路 /yiw。以重心 \(u\) 为根,若以 \(v\) 为根时树的结构与 \(u\) 相同,则容易得出 \(v\) 同样为重心,这样只用考虑 \(1/2\) 个重心的情况。
先考虑 \(1\) 个重心的情况。
则不存在换根之后相同的情况。只需要考虑无标号本质不同独立集数量。
设 \(f_{u,0/1}\) 表示 \(u\) 子树内,选/不选 \(u\) 的本质不同独立集数。
\[f_{u,0}\to f_{u,0}\times (f_{v,0}+f_{v,1})\\
f_{u,1}\to f_{u,1}\times f_{v,0}
\]
但是注意是无标号,这样的转移考虑了同构子树间选择方案的顺序。
若存在 \(v,v'\in S(u)\),\(T_v=T_{v'}\),\(v,v'\) 分别选择了 \(a,b\) 方案与 \(v,v'\) 分别选择 \(b,a\) 方案应记作一种。其中 \(S\) 为子节点集合,\(T_u\) 为以 \(u\) 为根的树。
考虑对同构的子树统一处理。
以第一种转移为例,假设有 \(x\) 个与 \(v\) 同构的子树(包含 \(v\)),相当于把 \(x\) 个球分到 \(f_{v,0}+f_{v,1}\) 个盒子,盒子允许为空的方案数。容易得到 \({x+f_{v,0}+f_{v,1}-1\choose f_{v,0}+f_{v,1}-1}\)。
则转移为:
\[f_{u,0}\to f_{u,0}\times {f_{v,0}+f_{v,1}+x-1\choose f_{v,0}+f_{v,1}-1}\\
f_{u,1}\to f_{u,1}\times {f_{v,0}+x-1\choose f_{v,0}-1}
\]
接下来考虑两个重心的情况。
考虑建立一个虚点向两重心连边,转化为一个重心的情况,虚点钦定不选,特殊的是在虚点转移时要考虑的是原本两重心不能同时选。
实现上不用建出虚点,直接分讨一下求答案即可。
UesugiErii
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
ll x=0,f=1;char ch=nc();
while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
#define pcount(x) __builtin_popcount(x)
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
const int mod=1e9+7;
ll qp(ll x,int y){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
const int N=5e5+5;
#define int ll
vector<int>e[N];
int rd,n,siz[N],mx[N],mn=1e9,r,r1,ifac[N],fac[N];ull h[N];
ull hsh(ull x){return x^=rd,x^=x<<17,x^=x>>13,x^=x<<5,x^=rd;}
void dfs(int u,int fa){
siz[u]=mx[u]=1;
for(int v:e[u])if(v^fa)
dfs(v,u),siz[u]+=siz[v],cmx(mx[u],siz[v]);
cmx(mx[u],n-siz[u]),cmn(mn,mx[u]);
}
unordered_map<ull,int>c[N],fl[2];
int f[N][2];
int C(int x,int y){
int res=1;
for(int i=x;i>y;i--)
res=res*i%mod;
return res*ifac[x-y]%mod;
}
void dfs1(int u,int fa){
h[u]=f[u][0]=f[u][1]=1;
for(int v:e[u])if(v^fa)
dfs1(v,u),h[u]+=hsh(h[v]),++c[u][h[v]];
for(auto it=c[u].begin();it!=c[u].end();it++){
int x=fl[0][it->fi],y=fl[1][it->fi],z=it->se;
f[u][0]=f[u][0]*C(x+y+z-1,x+y-1)%mod,
f[u][1]=f[u][1]*C(x+z-1,x-1)%mod;
}
fl[0][h[u]]=f[u][0],fl[1][h[u]]=f[u][1];
}
inline void UesugiErii(){
srand(time(0));rd=rand();
cin>>n;
for(int i=1,u,v;i<n;i++)
cin>>u>>v,e[u].pb(v),e[v].pb(u);
for(int i=fac[0]=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
ifac[n]=qp(fac[n],mod-2);
for(int i=n;i;i--)ifac[i-1]=ifac[i]*i%mod;
dfs(1,0);
for(int i=1;i<=n;i++)
if(mx[i]==mn)(!r?r:r1)=i;
if(r1){
dfs1(r,r1),dfs1(r1,r);
if(h[r]==h[r1])
cout<<(C(f[r][0]+1,f[r][0]-1)+f[r][0]*f[r][1]%mod)%mod;
else cout<<(f[r][0]*f[r1][1]%mod+f[r][1]*f[r1][0]%mod+f[r][0]*f[r1][0]%mod)%mod;
}else dfs1(r,0),cout<<(f[r][0]+f[r][1])%mod;
}
signed main(){
//IO();//cfast;
int _=1;//cin>>_;
for(;_;_--)UesugiErii();
return 0;
}

浙公网安备 33010602011771号