樹形DP 進階題

emmmm我之前那篇博客都是一些普及提高的樹形DP水題,基本都是一個模板能夠解決的問題。現在讓我們來進階一下。
**

T1

**

HOT-Hotels

傳送門

有一個樹形結構,每條邊的長度相同,任意兩個節點可以相互到達。選3個點。兩兩距離相等。有多少種方案?

難度:省選+/NOI-
這道題的難度並不是不能接受,一開始會覺得很難但是仔細想過之後會發現其實還好。

首先,我們要求任意三個點互相到達的距離相等,同時它是一個樹形結構
所以,仔細想一下可以得知,如果要讓三個點互相距離相同,那麼只會有一種方案,也就是,一箇中心店,即他們到這個中心點距離相同,然後它們之間互相的距離也是一樣的。
如果一時不能理解的話,請想過後再往下看。

那麼,這個這個中心點就成爲了我們做這道題的入手。
我們可以枚舉這個樹形結構的每一個點作爲根,那麼,在我們每次枚舉出的這棵樹裏,每一層的節點是不是就是高度相同?
也就是,這些點每三個就可以作爲一個方案,
然後我們的任務就是來求方案了
根據小學乘法原理,
譬如這個根有三個子樹,在這一層 的節點數分別是a,b,c,那麼方案數是不是就是a*b*c?
同理如果這個根再多一個子樹那麼方案數是不是還要多
abd+acd+bcd
(ab+ac+bc)d
那麼再多一顆子樹也依然如此。

所以這就是我們的突破口了,
用一個sum2數組維護a*b+b*c+a*c………等這一式子;每次新得到的節點數爲K
那麼新增加的答案數爲sum2*K;
設sum1爲當前這一層當前子樹之前的所有節點之和,
設tot[i]爲當前子樹第i層的節點數
那麼框架就是
1.枚舉根節點k
2.枚舉每一棵子樹,計算第i層的tot[i];
3.計算部分:
ans=ans+tot[i]sum2[i];
sum2[i]=sum2[i]+sum1[i]tot[i]
sum1[i]=sum1[i]+tot[i]
tot[i]=0//

然後就是每次枚舉樹根之後,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;
}

大佬解法好
感謝大佬

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章