bzoj1494: [NOI2007]生成树计数

来源:互联网 发布:淘宝运动鞋女质量 编辑:程序博客网 时间:2024/06/12 23:55

传送门
将k个点的连通性用最小表示法压成状态,那么最多有52种状态
最小表示法中,f[i]表示最小的与其联通的点编号。
计算出每个状态的生成树个数,作为初始行向量A
对于每种状态考虑新加入一个点并向这k个点连边,每种连法可以转移到哪些状态,得到转移矩阵B
那么答案就是A∗Bn[所有点都连通的状态]
就是代码炒鸡长。

#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define mo 65521#define uint unsigned int#define ll long longusing namespace std;int k,tot,pos[33333];ll n;uint A[60],ans;struct mat{    uint a[60][60];    mat(int fl){        memset(a,0,sizeof(a));        for (int i=1;i<=tot;i++)            a[i][i]=fl;    }    uint* operator [](int x){        return a[x];    }    friend mat& operator *=(mat &x,mat y){        mat z(0);        for (int i=1;i<=tot;i++)            for (int j=1;j<=tot;j++)                for (int k=1;k<=tot;k++)                    z[i][j]=(z[i][j]+x[i][k]*y[k][j])%mo;        return x=z;     }}a(0);mat power(mat x,ll y){    mat s(1);    for (;y;y/=2,x*=x)        if (y&1) s*=x;    return s;}void express(int a[],int x){    for (int i=0;i<k;i++)        a[i]=(x>>i*3)&7;}int impress(int a[]){    int s=0;    for (int i=0;i<k;i++)        s|=a[i]<<i*3;    return s;}void stdsize(int a[]){    static int b[10];    int cnt=0;    memset(b,0,sizeof(b));    for (int i=0;i<k;i++)        if (!b[a[i]]) b[a[i]]=++cnt;    for (int i=0;i<k;i++) a[i]=b[a[i]];}bool ok(int x){    static int a[10];    int now=1;    express(a,x);    for (int i=0;i<k;i++)        if (!a[i]||a[i]>now) return 0;        else if (a[i]==now) now++;    return 1;}void calc1(int x){    static int A[10],b[10],cnt[10];    int lim=0;    express(A,x);    memset(cnt,0,sizeof(cnt));    for (int i=0;i<k;i++){        cnt[A[i]]++;        lim=max(lim,A[i]);    }    for (int _x=0;_x<1<<lim;_x++){        if (cnt[1]==1&&_x%2==0) continue;        int tmp=1;        memcpy(b,A,sizeof(A));        b[k]=9;        for (int i=1;i<=lim;i++)            if (_x&(1<<i-1)) tmp*=cnt[i];        for (int i=0;i<k;i++)            if (_x&(1<<A[i]-1)) b[i]=9;        stdsize(b+1);        a[pos[x]][pos[impress(b+1)]]=tmp;    }}int power(int x,int y){    int s=1;    for (;y>0;y--) s*=x;    return s; }void calc2(uint A[],int x){    static int a[10],cnt[10];    int s=1;    express(a,x);    memset(cnt,0,sizeof(cnt));    for (int i=0;i<k;i++) cnt[a[i]]++;    for (int i=1;cnt[i];i++)        s*=power(cnt[i],cnt[i]-2);    A[pos[x]]=s;}int main(){    scanf("%d%lld",&k,&n);    if (k>n) k=n;    for (int i=0;i<1<<k*3;i++)        if (ok(i)) pos[i]=++tot;    for (int i=0;i<1<<k*3;i++)        if (pos[i]){            calc1(i);            calc2(A,i);        }    mat B=power(a,n-k);    for (int i=1;i<=tot;i++)        ans=(ans+A[i]*B[i][1])%mo;    printf("%u",ans);}
0 0
原创粉丝点击