emmmm我之前那篇博客都是一些普及提高的樹形DP水題,基本都是一個模板能夠解決的問題。現在讓我們來進階一下。
**
T1
**
HOT-Hotels
有一個樹形結構,每條邊的長度相同,任意兩個節點可以相互到達。選3個點。兩兩距離相等。有多少種方案?
難度:省選+/NOI-
這道題的難度並不是不能接受,一開始會覺得很難但是仔細想過之後會發現其實還好。
首先,我們要求任意三個點互相到達的距離相等,同時它是一個樹形結構
所以,仔細想一下可以得知,如果要讓三個點互相距離相同,那麼只會有一種方案,也就是,一箇中心店,即他們到這個中心點距離相同,然後它們之間互相的距離也是一樣的。
如果一時不能理解的話,請想過後再往下看。
那麼,這個這個中心點就成爲了我們做這道題的入手。
我們可以枚舉這個樹形結構的每一個點作爲根,那麼,在我們每次枚舉出的這棵樹裏,每一層的節點是不是就是高度相同?
也就是,這些點每三個就可以作爲一個方案,
然後我們的任務就是來求方案了
根據小學乘法原理,
譬如這個根有三個子樹,在這一層 的節點數分別是a,b,c,那麼方案數是不是就是a*b*c?
同理如果這個根再多一個子樹那麼方案數是不是還要多
即
那麼再多一顆子樹也依然如此。
所以這就是我們的突破口了,
用一個sum2數組維護a*b+b*c+a*c………等這一式子;每次新得到的節點數爲K
那麼新增加的答案數爲sum2*K;
設sum1爲當前這一層當前子樹之前的所有節點之和,
設tot[i]爲當前子樹第i層的節點數
那麼框架就是
1.枚舉根節點k
2.枚舉每一棵子樹,計算第i層的tot[i];
3.計算部分:
然後就是每次枚舉樹根之後,sum1sum2要清零。
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010;
int n,m,cnt,head[maxn],sum1[maxn],sum2[maxn],dep,tot[maxn];
long long ans;
inline int read()
{
int X=0,w=0; char c=0;
while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
return w?-X:X;
}
struct node
{
int v,nxt;
}e[maxn<<1];
void add(int u,int v)
{
cnt++;
e[cnt].nxt=head[u];
e[cnt].v=v;
head[u]=cnt;
}
void getfun(int v,int u,int deep)
{
dep=max(dep,deep);
tot[deep]++;
for (int i=head[v]; i; i=e[i].nxt)
{
int y=e[i].v;
if (y==u) continue;
getfun(y,v,deep+1);
}
}
int main()
{
n=read();
for (int i=1; i<n; i++)
{
int x,y;
x=read(),y=read();
add(x,y);
add(y,x);
}
for (int i=1; i<=n; i++)
{
memset(sum1,0,sizeof(sum1));
memset(sum2,0,sizeof(sum2));
for (int j=head[i]; j; j=e[j].nxt)
{
int v=e[j].v;
dep=0;
getfun(v,i,1);
for(int k=1;k<=dep;k++)
{
ans+=tot[k]*sum2[k];
sum2[k]=sum2[k]+sum1[k]*tot[k];
sum1[k]=sum1[k]+tot[k];
tot[k]=0;
}
}
}
cout<<ans;
}
大佬解法好
感謝大佬