bzoj 1005 明明的煩惱 【Prufer序列】

啊啊啊啊,什麼東西都堆到noi前幾天來學真的是要完啊,關鍵是我還在浪啊TATAT
日常吐槽QwQ

題目大意:給定一棵樹其中某些點的度數,求有多少種樹滿足要求

orz大爺的博客%%%

prufer序列
對於一棵樹,每次選擇編號最小的葉節點,刪除它,並將與它相連的那個節點編號加入序列,直到只剩下兩個節點爲止

事實證明,樹和prufer序列是一一對應的

性質:若一個點的度數爲d,那麼它將會在序列中出現d - 1次

然後就是組合數學啦23333

令 m = n2ki=1(di1) ,num 爲不確定度數的點的個數
ans = (n2)ki=1(di1)!mnumm

高精orz

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define N 3000
using namespace std;

int n,len,m,tot,x;
int a[N],ans[N];

void mul(int x)
{
    int r = 0;
    for (int i = 0;i <= len;i ++)
    {
        ans[i] = ans[i] * x + r;
        r = ans[i] / 10;
        ans[i] %= 10;
    }
    for (;r;r /= 10) ans[++ len] = r % 10;
}

int main()
{
    scanf("%d",&n),tot = n - 2;
    for (int i = 1;i <= n;i ++)
    {
        scanf("%d",&x);
        if (x == -1) m ++;
        else if (x > 1)
        {
            for (int j = 2;j < x;j ++) a[j] --;
            tot -= x - 1;
        }
    }
    for (int i = 2;i <= n - 2;i ++) a[i] ++;
    for (int i = 2;i <= tot;i ++) a[i] --;
    a[m] += tot,ans[0] = 1;
    for (int i = n;i >= 2;i --)
    {
        for (int j = 2;j * j <= i;j ++)
            if (i % j == 0) {a[j] += a[i],a[i/j] += a[i],a[i] = 0;break;}
        while (a[i] --) mul(i);
    }
    for (int i = len;i >= 0;i --) printf("%d",ans[i]);

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