• 线性代数(矩阵乘法):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
    ",B.mat[1][1]);
    116     return 0;
    117 }
    尽最大的努力,做最好的自己!
  • 相关阅读:
    OpenJudge计算概论-寻找山顶
    OpenJudge计算概论-配对碱基链
    OpenJudge计算概论-分配病房
    OpenJudge计算概论-计算鞍点
    OpenJudge计算概论-错误探测
    OpenJudge计算概论-文字排版
    OpenJudge计算概论-二维数组右上左下遍历
    OpenJudge-计算点的距离并排序
    OpenJudge计算概论-找最大数序列
    Openjudge计算概论-奇数单增序列
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5568906.html
Copyright © 2020-2023  润新知