【省選模擬】Tree(DP)(分類討論)

傳送門

  • 分類討論有點 nbnb,考慮 dpudp_{u} 表示把 uu 是當前的左上角,且之前的全部填滿,將 uu 的子樹填進去的方案數

  • 如果兒子個數爲 1,那麼存在以下情況
    -在這裏插入圖片描述
    係數分別是 1,dpv,1,dpx,dpz1,dp_v,1,dp_x,dp_z,合法的鏈滿足只有中間兩個點兒子個數不爲 1,其餘兒子數均爲 1 或 0,這個可以預處理出來

  • 如果兒子個數爲 2,考慮哪個在上哪個在右即可轉移,和上一類的最後一種類似
    複雜度 O(n)O(n)

#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define fi first
#define se second
using namespace std;
namespace IO{
	cs int Rlen=1<<22|1;
	inline char gc(){
		static char buf[Rlen],*p1,*p2;
		(p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
		return p1==p2?EOF:*p1++;
	}
	int read(){
		int x=0; bool f=false; char c=gc();
		while(!isdigit(c)) f=c=='-', c=gc();
		while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
		return f?-x:x;
	}
} using namespace IO;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
typedef pair<int, int> pi;
cs int N = 3e5 + 50;
int n; vector<int> G[N];
int ch[N][2], fa[N], dep[N];
void pre_dfs(int u, int f){
	for(int v : G[u]) if(v ^ f) 
	fa[v]=u, dep[v]=dep[u]+1, pre_dfs(v,u);
} int dp[N];
vector<pi> S[N];
int len[N]; // to leaf 
int Sublen[N]; // to key point 
int bot[N];
vector<int> pt[N];
void pre_work(){
	memset(len,-1,sizeof(len));
	for(int i=1; i<=n; i++) 
	if(G[i].size()==0){
		int x=i, d=1; 
		while(x){ len[x]=d; bot[x]=i; pt[i].pb(x); x=fa[x]; ++d; if(G[x].size()>1) break;  }
	} 
	static int id[N];
	for(int i=1; i<=n; i++) id[i]=i;
	sort(id+1, id+n+1, [](cs int &i, cs int &j){ return dep[i] > dep[j]; });
	for(int i=1; i<=n; i++){
		int u=id[i]; if(~len[u]) continue;
		if(G[u].size()>1) continue;
		if(Sublen[u]) continue; int d=1,x=u;
		while(u){ Sublen[u]=d; bot[u]=x; pt[x].pb(u); u=fa[u]; ++d; if(G[u].size()>1) break; }
	}
	for(int u=1; u<=n; u++)if(Sublen[u] && len[u]==-1){
		int v=G[bot[u]][0]; assert(G[v].size()==2); 
		for(int w : G[v])
		for(int z : G[w])
		if(len[z] == Sublen[u]) S[u].pb(pi(w,z));
		for(int w : G[v]) if(len[w] == Sublen[u]-1) S[u].pb(pi(v,w));
	}
}
int get(int u, int v){ 
	assert(G[u].size()==2);
	return G[u][0]==v ? G[u][1] : G[u][0];
}
int pnt(int v1, int v2){
	if(len[v1]<len[v2]) swap(v1,v2);
	assert(len[v1]!=len[v2]);
	return pt[bot[v1]][len[v1]-len[v2]-1];
}
int sec_pnt(int v, int len){
	return G[pt[bot[v]][Sublen[v]-len]][0];
}
void spc_work(int u, int v1, int v2){
	if(len[v1]==-1 && len[v2]==-1) return;
	if(~len[v1] && ~len[v2]){
		if(len[v1]==len[v2]) Add(dp[u],1);
		else Add(dp[u],dp[pnt(v1,v2)]);
	}
	else{
		if(~len[v2]) swap(v1,v2);
		if(len[v1]<=Sublen[v2]) Add(dp[u],dp[sec_pnt(v2,len[v1])]);
	}
}
void work1(int u){
	int v = G[u][0];
	if(G[v].size()==0) return dp[u]=2,void();
	if(G[v].size()==1) Add(dp[u],dp[G[v][0]]);
	Add(dp[u],dp[v]);
	if(~len[u] && ((len[u]&1)^1)) return Add(dp[u],1),void(); 
	for(auto T : S[u]){
		int t = T.fi, son = T.se;
		if(G[t].size() == 1){
		int v = get(fa[t],t);
		Add(dp[u], dp[v]);
		} 
		else{
			if(G[fa[t]].size() == 1){
			int v = get(t,son);
			Add(dp[u], dp[v]);
			} 
			else{
				int v1 = get(fa[t],t), v2 = get(t,son);
				spc_work(u,v1,v2);
			}
		}
	}
}
void calc(int u, int v1, int v2){
	if(G[v1].size()==0) return Add(dp[u],dp[v2]),void();
	if(G[v1].size()==2) return; v1=G[v1][0];
	spc_work(u,v2,v1);
}
void work2(int u){
	int v1=G[u][0], v2=G[u][1];
	if(len[v1]==-1 && len[v2]==-1) return;
	calc(u,v1,v2); calc(u,v2,v1);
}
void work(int u){
	for(int v : G[u]) if(v) work(v);
	if(G[u].size()==0) dp[u]=1;
	if(G[u].size()==1) work1(u);
	if(G[u].size()==2) work2(u);
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	n=read();
	for(int i=1,x,y; i<n; i++)
	x=read(), y=read(), G[x].pb(y), G[y].pb(x);
	pre_dfs(1,0); if(G[1].size()>2) return puts("0"),0;
	for(int i=1; i<=n; i++){
		if(G[i].size()>3) return puts("0"),0; vector<int> tmp;
		for(int t : G[i]) if(t ^ fa[i]) tmp.pb(t); G[i] = tmp;
	} pre_work();
	work(1); cout<<dp[1]; exit(0); return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章