JZOJ 4757 樹上摩托

題目大意

給定大小爲n的一棵樹,通過刪除一些邊的方式來拆分這棵樹。問有多少種方法使拆分出的每一個部分大小相等。注意一條邊也不刪也可以算一種方案。輸入量很大,要用快速讀入。

n<=10^6
時間限制 2s
空間限制 1024M

解題思路

首先這些樹的大小一定是n的約數,並且當樹的大小k確定時,分割方案也一定是唯一的。所以我們可以枚舉k,再看看有多少棵樹的大小爲k的整數倍,如果這個數量爲n/k,那麼答案就可以加一。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;

void read(int &x)
{
    char c;
    x=0;
    for(c=getchar();c<'0' || c>'9';c=getchar());
    for(;c>='0' && c<='9';c=getchar()) x=x*10+c-'0';
    return;
}

struct poi
{
    int x;
    poi *nex;
} *a[maxn];
int i,k,n,x,y,s,ans,d[maxn],f[maxn],fa[maxn],siz[maxn];
void link(int x,int y)
{
    poi *p=new poi;
    p->x=y;
    p->nex=a[x];
    a[x]=p;
    return;
}
void bfs()
{
    int i=0,j=1;
    poi *p=new poi;
    f[1]=1;
    while (i<j)
    {
        i++;
        int u=f[i];
        siz[u]=1;
        for(p=a[u];p;p=p->nex)
            if (p->x!=fa[u])
            {
                fa[p->x]=u;
                f[++j]=p->x;
            }
    }
    return;
}
int main()
{
    scanf("%d",&n);
    fr(i,1,n-1)
    {
        read(x),read(y);
        link(x,y),link(y,x);
    }
    bfs();
    poi *p=new poi;
    for(k=n;k;k--)
    {
        i=f[k];
        for(p=a[i];p;p=p->nex)
            if (p->x!=fa[i])
                siz[i]+=siz[p->x];
    }
    fr(i,1,n) d[siz[i]]++;

    fr(k,1,n)
        if (n%k==0)
        {
            s=0;
            fr(i,1,n/k) s+=d[i*k];
            if (s==n/k) ans++;
        }
    printf("%d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章