BZOJ 1494 生成树计数(生成树计数-矩阵)

时间:2023-03-09 08:54:16
BZOJ 1494 生成树计数(生成树计数-矩阵)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1494

题意:

BZOJ 1494 生成树计数(生成树计数-矩阵)

思路:

BZOJ 1494 生成树计数(生成树计数-矩阵)

int SIZE;

struct matrix
{
    i64 a[N][N];

    void init(int x)
    {
        clr(a,0);
        if(x)
        {
            int i;
            FOR0(i,SIZE) a[i][i]=1;
        }
    }

    matrix operator*(matrix p)
    {
        matrix ans;
        ans.init(0);
        int i,j,k;
        FOR0(k,SIZE) FOR0(i,SIZE) FOR0(j,SIZE)
        {
            ans.a[i][j]+=a[i][k]*p.a[k][j]%mod;
            ans.a[i][j]%=mod;
        }
        return ans;
    }

    matrix pow(i64 n)
    {
        matrix ans,p=*this;
        ans.init(1);
        while(n)
        {
            if(n&1) ans=ans*p;
            p=p*p;
            n>>=1;
        }
        return ans;
    }
};

matrix a;

const int val[]={1,1,1,3,16,125};
int status[N],hash[1<<15];
int S[N],K;
i64 n;
i64 c[N];

void DFS(int dep,int st)
{
    if(dep==K)
    {
        c[SIZE]=1;
        int a[10]={0},i;
        FOR0(i,K) a[st>>(i*3)&7]++;
        FOR0(i,K) c[SIZE]*=val[a[i]];
        status[SIZE]=st;
        hash[st]=SIZE++;
        return;
    }
    int temp=-1,i;
    FOR0(i,dep) upMax(temp,st>>(i*3)&7);
    for(i=0;i<=temp+1;i++)
    {
        DFS(dep+1,st<<3|i);
    }
}

int find(int x)
{
    if(S[x]!=x) S[x]=find(S[x]);
    return S[x];
}

int cal()
{
    int visit[N]={0},tot=0,st=0,i,j;
    for(i=K-1;i>=0;i--) if(!visit[i])
    {
        visit[i]=1;
        st|=tot<<(i*3);
        for(j=i-1;j>=0;j--) if(find(i+1)==find(j+1))
        {
            visit[j]=1,st|=tot<<(j*3);
        }
        tot++;
    }
    return hash[st];
}

void deal(int s,int mask)
{
    int i,j;
    for(i=0;i<=K;i++) S[i]=i;
    for(i=0;i<K;i++) for(j=i+1;j<K;j++)
    {
        if((status[s]>>(i*3)&7)==(status[s]>>(j*3)&7))
        {
            int px=find(i);
            int py=find(j);
            if(px!=py) S[px]=py;
        }
    }
    for(i=0;i<K;i++) if(mask&(1<<i))
    {
        int px=find(i);
        int py=find(K);
        if(px==py) return; //保证无环存在
        S[px]=py;
    }
    for(i=1;i<=K;i++) if(find(i)==find(0)) break;
    if(i>K) return; //保证连通性
    a.a[s][cal()]++;
}

int main()
{
    while(scanf("%d%lld",&K,&n)!=-1)
    {
        a.init(0);
        SIZE=0;
        DFS(0,0);
        int i,j;
        FOR0(i,SIZE) FOR0(j,1<<K) deal(i,j);
        a=a.pow(n-K);
        i64 ans=0;
        FOR0(i,SIZE) (ans+=c[i]*a.a[i][0])%=mod;
        printf("%lld\n",ans);
    }
}