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
- bzoj1494: [NOI2007]生成树计数
- 生成树计数 NOI2007
- BZOJ 1494: [NOI2007]生成树计数
- 【noi2007】生成树计数 连通性DP
- bzoj 1494: [NOI2007]生成树计数
- BZOJ 1494 [NOI2007]生成树计数
- bzoj1494 生成树计数(状压dp+生成树+矩阵倍增)
- 【基于连通性的状态压缩DP】【NOI2007】生成树计数
- [NOI2007]生成树计数(状压dp+矩阵加速)
- BZOJ 1494 NOI2007 生成树计数 状压DP+矩阵乘法
- 生成树计数
- NOI2008 生成树计数
- 《生成树计数》预处理
- 生成树计数
- 图论-生成树计数
- 生成树计数问题
- 生成树的计数
- 生成树计数
- 数据库的常用的三大范式及事务的四个特征
- Hibernate 关系映射整理
- 【LEET-CODE】11. Container With Most Water
- mybatis使用spring-druid数据源连接池配置log4j打印sql语句以及开启监控平台
- C++知识点
- bzoj1494: [NOI2007]生成树计数
- Linux下MySQL数据库基本操作
- 博客停止更新,转移至 http://www.bendawang.site/
- 剑指offer 49. 把字符串转换成整数
- Python基础一
- 数据库垂直拆分
- Servlet中不可不知的Session技术
- 彻底弄懂Java中的equals()方法以及与"=="的区别
- ps和grep 的用法