博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj1494 生成树计数 (dp+矩阵快速幂)
阅读量:4567 次
发布时间:2019-06-08

本文共 3559 字,大约阅读时间需要 11 分钟。

题面欺诈系列...

因为一个点最多只能连到前k个点,所以只有当前的连续k个点的连通情况是对接下来的求解有用的

那么就可以计算k个点的所有连通情况,dfs以下发现k=5的时候有52种。

我们把它们用类似于并查集的方式表达(比如12132代表点1和点3连通,2和5连通,3自己),然后再压缩一下。

但要注意的是,12132和23213这两种实际对应的是一种连通情况,我们只要把它都化成字典序最小的那种就可以了

然后考虑增加一个新点以后状态的转移,可以枚举这个点与前k个点(始状态S)的连边情况,其中有一些是不合法的:

  1.连到了两个本来就连通的点上(导致成环)

  2.在1号点不与其他点连通的情况下,没有连到1号点(导致不连通)

然后再根据连边情况得到终状态E,将trans[S][E]++。最后trans[i][j]表示的就是加入一个点后由i状态到j状态的方案数

那么就可以得到递推式$f[i][j]=\sum^{总状态数}_{k=1}{f[i-1][k]*trans[k][j]}$,其中f[i][j]表示以i为结尾的k个点状态是j的方案数

那么答案就是f[N][1](假设1是都连通的状态)

然后初值就应该是f[K][i]=i状态的方案数,其中i状态的方案数为它其中每个联通块方案数的乘积。

那么联通块的方案数怎么算呢?其实题面已经说了...n个点的方案数就是$n^{n-2)}$

然后就可以愉快地dp一脸啦

容易发现递推的形式其实和矩阵乘法是相同的,把f[i]和trans看作矩阵,就是$f[N]=f[K]*trans^{N-K}$

然后就可以倍增做矩阵快速幂了。方法和整数的快速幂是一样的。

复杂度:

  K=5的状态数接近50,$log(10^{15})$接近50。

  所以基本上是$50^3*50=6250000$的。

代码写的很蛋疼...

1 #include
2 #include
3 #include
4 #include
5 #include
6 #define LL long long 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 const LL maxn=1e15+5,maxs=55,p65=50000,mod=65521; 10 11 LL rd(){ 12 LL x=0;char c=getchar();int neg=1; 13 while(c<'0'||c>'9'){
if(c=='-') neg=-1;c=getchar();} 14 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 15 return x*neg; 16 } 17 18 LL N;int K,sct,num[6]={
0,1,1,3,16,125}; 19 LL f[maxs]; 20 LL trans[2][maxs][maxs],out[2][maxs][maxs]; 21 struct ST{ 22 int s[6]; 23 ST(int x=0){memset(s,x,sizeof(s));} 24 }sta[maxs]; 25 struct Mat{ 26 LL m[maxs][maxs]; 27 Mat(){memset(m,0,sizeof(m));} 28 }; 29 int mp[p65]; 30 31 void print(ST s){ 32 for(int i=1;i<=K;i++) printf("%d",s.s[i]); 33 } 34 int STtoInt(ST s){ 35 int x=0;for(int i=1;i<=K;i++) x=x*6+s.s[i];return x; 36 } 37 38 ST toLeast(ST s){ 39 ST flag=ST(-1),re=ST();int n=0; 40 for(int i=1;i<=K;i++){ 41 if(flag.s[s.s[i]]==-1) flag.s[s.s[i]]=n++; 42 re.s[i]=flag.s[s.s[i]]; 43 }return re; 44 } 45 46 void dfs1(int x,ST s,int m){ 47 if(x>=K+1){ 48 sta[++sct]=s;mp[STtoInt(s)]=sct;return; 49 } 50 for(int i=0;i<=m+1;i++){ 51 s.s[x]=i; 52 dfs1(x+1,s,max(m,i)); 53 } 54 } 55 56 void dfs2(int x,ST s,ST from){ 57 if(x>=K+1){ 58 bool flag[6],bb=s.s[1];ST to=ST();int mi=5; 59 memset(flag,0,sizeof(flag)); 60 //print(from);printf("\t");print(s);printf("\n"); 61 for(int i=1;i<=K;i++){ 62 if(!s.s[i]) continue; 63 if(flag[from.s[i]]) return; 64 flag[from.s[i]]=1;mi=min(mi,from.s[i]); 65 } 66 for(int i=2;i<=K;i++){ 67 to.s[i-1]=flag[from.s[i]]?mi:from.s[i]; 68 if(from.s[1]==to.s[i-1]) bb=1; 69 }to.s[K]=mi; 70 if(!bb) return; 71 to=toLeast(to); 72 //print(from);printf("\t");print(s);printf("\t");print(to);printf("\n"); 73 trans[0][mp[STtoInt(from)]][mp[STtoInt(to)]]++; 74 75 }else{ 76 dfs2(x+1,s,from);s.s[x]=1;dfs2(x+1,s,from); 77 } 78 } 79 80 void sets(){ 81 for(int i=1;i<=sct;i++){ 82 dfs2(1,ST(),sta[i]); 83 //for(int j=1;j<=sct;j++) printf("%d ",trans[0][i][j]);printf("\n"); 84 ST cnt=ST(); 85 for(int j=1;j<=K;j++) cnt.s[sta[i].s[j]]++; 86 f[i]=1;for(int j=0;j
>=1;b^=1;112 }LL ans=0;113 for(i=1;i<=sct;i++){114 ans=(ans+f[i]*out[c^1][i][1])%mod;115 }printf("%d\n",ans);116 }117 118 int main(){119 int i,j,k;120 K=rd(),N=rd();121 dfs1(2,ST(),0);sets();122 solve();123 return 0;124 }

 

转载于:https://www.cnblogs.com/Ressed/p/9461115.html

你可能感兴趣的文章
JavaScipt30(第七个案例)(主要知识点:数组some,every,findIndex方法)
查看>>
Android 采用HttpClient提交数据到服务器
查看>>
EL表达式概述
查看>>
word中批量修改图片大小
查看>>
Ext4 中 日期和时间的控件
查看>>
最长子序列问题
查看>>
python中一些有用的函数------持续更新中
查看>>
第三次作业—张淑华
查看>>
python 实现字符串的切片功能
查看>>
Centos 文件权限修改
查看>>
使用Amazon Simple Queues Service (SQS)实现与AutoCAD远程交互
查看>>
oracle 游标
查看>>
滚动条滚动到最底部的方法总结
查看>>
想不劳而获的人太多了,而我就是其中一个
查看>>
hexo改造
查看>>
Python模块NumPy中的tile(A,rep) 函数
查看>>
JS实现打开本地文件或文件夹 ActiveXObject
查看>>
python中split函数的使用
查看>>
优化 SQL SELECT 语句性能
查看>>
Spring3 MVC 类型转换
查看>>