线性代数(矩阵乘法):NOI 2007 生成树计数
Posted 既然选择了远方,便只顾风雨兼程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性代数(矩阵乘法):NOI 2007 生成树计数相关的知识,希望对你有一定的参考价值。
这道题就是深搜矩阵,再快速幂。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <map> 5 using namespace std; 6 const int maxn=200; 7 const int mod=65521; 8 struct Matrix{ 9 long long mat[maxn][maxn]; 10 int r,c; 11 Matrix(int r_=0,int c_=0,int on=0){ 12 memset(mat,0,sizeof(mat)); 13 r=r_;c=c_; 14 if(on)for(int i=1;i<=r;i++)mat[i][i]=1; 15 } 16 Matrix operator *(Matrix a){ 17 Matrix ret(r,a.c); 18 long long l; 19 for(int i=1;i<=r;i++) 20 for(int k=1;k<=c;k++){ 21 l=mat[i][k]; 22 for(int j=1;j<=a.c;j++) 23 (ret.mat[i][j]+=(l*a.mat[k][j])%mod)%=mod; 24 } 25 return ret; 26 } 27 Matrix operator ^(long long k){ 28 Matrix ret(r,c,1),x(r,c); 29 for(int i=1;i<=r;i++) 30 for(int j=1;j<=c;j++) 31 x.mat[i][j]=mat[i][j]; 32 while(k){ 33 if(k&1) 34 ret=ret*x; 35 k>>=1; 36 x=x*x; 37 } 38 return ret; 39 } 40 }A,B; 41 42 long long n; 43 map<int,int>ID; 44 map<int,bool>used; 45 int k,e,e1,E[maxn][2]; 46 int cnt,st[1<<17],mem[1<<17]; 47 int fa[maxn],sz[maxn],vis[maxn]; 48 int Find(int x){ 49 return x==fa[x]?x:fa[x]=Find(fa[x]); 50 } 51 bool Check(int s){ 52 for(int i=1;i<maxn;i++) 53 fa[i]=i,sz[i]=1; 54 for(int i=0;i<e+e1;i++) 55 if(s&(1<<i)){ 56 int u=Find(E[i][0]),v=Find(E[i][1]); 57 if(u!=v){fa[u]=v;sz[v]+=sz[u];} 58 else return false; 59 } 60 return true; 61 } 62 63 void Solve(int x){ 64 for(int i=1;i<=x;i++) 65 for(int j=i+1;j<=x;j++) 66 E[e][0]=i,E[e][1]=j,e++; 67 for(int i=1;i<=x;i++) 68 E[e+e1][0]=i,E[e+e1][1]=x+1,e1++; 69 70 for(int s=(1<<e)-1,num;s>=0;s--) 71 if(Check(s)){ 72 memset(vis,0,sizeof(vis));num=0; 73 for(int i=1;i<=x;i++){ 74 if(vis[Find(i)])continue; 75 vis[Find(i)]=++num; 76 } 77 num=0; 78 for(int i=1;i<=x;i++) 79 num=num*10+vis[Find(i)]; 80 if(ID[num])B.mat[ID[num]][1]+=1; 81 else{ 82 A.r+=1;A.c+=1;B.r+=1; 83 B.mat[ID[num]=B.r][1]=1; 84 st[++cnt]=s;mem[cnt]=num; 85 } 86 } 87 88 for(int t=1,s;t<=cnt;t++){ 89 for(int p=(1<<e1)-1,num;p>=0;p--){ 90 s=st[t]^(p<<e); 91 if(Check(s)&&sz[Find(1)]!=1){ 92 memset(vis,0,sizeof(vis));num=0; 93 for(int i=2;i<=x+1;i++){ 94 if(vis[Find(i)])continue; 95 vis[Find(i)]=++num; 96 } 97 num=0; 98 for(int i=2;i<=x+1;i++) 99 num=num*10+vis[Find(i)]; 100 A.mat[ID[num]][ID[mem[t]]]+=1; 101 } 102 } 103 } 104 return; 105 } 106 107 int main(){ 108 #ifndef ONLINE_JUDGE 109 freopen("count.in","r",stdin); 110 freopen("count.out","w",stdout); 111 #endif 112 scanf("%d%lld",&k,&n); 113 k=min(1ll*k,n);Solve(k);B.c=1; 114 A=A^((n-k)%(1ll*(mod+1)*(mod-1)));B=A*B; 115 printf("%lld\n",B.mat[1][1]); 116 return 0; 117 }
以上是关于线性代数(矩阵乘法):NOI 2007 生成树计数的主要内容,如果未能解决你的问题,请参考以下文章
luogu P2144 [FJOI2007] 轮状病毒 矩阵(da)生成树(biao)+高精
P1397 [NOI2013] 矩阵游戏(矩阵乘法&欧拉定理)