线性代数(矩阵乘法):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)+高精

BZOJ1491: [NOI2007]社交网络

Bzoj1016: [JSOI2008]最小生成树计数

P1397 [NOI2013] 矩阵游戏(矩阵乘法&欧拉定理)

P1397 [NOI2013] 矩阵游戏(矩阵乘法&欧拉定理)

BZOJ_1016_[JSOI2008]_最小生成树计数_(dfs+乘法原理)