1. 程式人生 > >[gym101933]King's Colors 計數問題

[gym101933]King's Colors 計數問題

/*
    [gym101933]King's Colors
    樹上染色,一共k種顏色都要用到。相鄰節點顏色不同,問方案數。
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1000000007;
const int mmax=2555;
const int nmax=2555;

int n,k;

/** 基礎加邊*/
int etot=0,to[mmax],nex[mmax],head[nmax];
void addedge(int u,int v){
    to[++etot]=v,nex[etot]=head[u],head[u]=etot;
}

/** vir[i]: 使用i種顏色的方案數,包括小於等於k
    rea[i]:剛剛好使用i種顏色的方案數*/
ll vir[nmax],rea[nmax];

/** dfs:當前節點rt用1種顏色方案(一共k種顏色可選)
    dfs計算vir陣列。
    vir[i]=dfs(0,i)*i;
*/
ll dfs(int rt,int k){
    if(!head[rt])return 1;
    ll son_tot=1;
    for(int i=head[rt];i;i=nex[i]){
        son_tot=son_tot*(k-1)%mod*dfs(to[i],k)%mod;
        //兒子節點除了當前節點選色其他k-1種顏色都能用。
    }
    return son_tot;
}

/** 預處理計算i^(-1)%mod*/
ll ver[nmax];
ll quick_pow(ll a,ll x){
    ll ans=1;
    while(x){
        if(x&1) ans=ans*a%mod;
        a=a*a%mod;
        x>>=1;
    }return ans;
}
void init_ver(){
    for(int i=1;i<=k;i++){
        ver[i]=quick_pow(i,mod-2);
    }
}

int main(){
    int pa;
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++){
        scanf("%d",&pa);
        addedge(pa,i);
    }
    init_ver();

    for(int i=2;i<=k;i++){
        vir[i]=i*dfs(0,i)%mod;
        rea[i]=vir[i];
        ll C=i;
        for(int j=2;j<i;j++){
            C=C*(i-j+1)%mod*ver[j]%mod;
            rea[i]=(rea[i]-C*rea[j]%mod+mod)%mod;
            //real[i]=vir[i]-sigma(2<=j<i)C(i,j)*real[j]
        }
    }
    printf("%I64d\n",rea[k]);
    return 0;
}