zoukankan      html  css  js  c++  java
  • BZOJ 1494 [NOI2007]生成树计数 矩阵乘法+DP

    题解:

    这种数据范围果断矩阵乘法,其实dp什么的也特别显然,就是求转移矩阵特别恶心。

    最小表示法(表示现学的压力比较大)表示连通性。

    能多暴力就多暴力的枚举,反正数据范围小~

    唯一需要注意的是转移的时候有两种情况是不合法的:

    1、第(i-k)个点不和第(i-k+1)到i个点连通

    2、第i个点连到已经在一个连通块中的两个点

    wa了半天,然后不想做了的时候突然发现ac了。。莫名其妙。。。

    代码比较丑陋。。

    View Code
      1 #include <iostream>
      2 #include <cstdlib>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 
      7 #define N 10
      8 #define SIZE 60
      9 #define mod 65521
     10 
     11 using namespace std;
     12 
     13 struct MT
     14 {
     15     int x,y;
     16     long long mt[SIZE][SIZE];
     17 }ans,zy;
     18 
     19 int hash[100010],antihash[100010];
     20 int m,fa[N],col[N],cnt;
     21 long long n;
     22 bool map[N][N],vis[N][N];
     23 
     24 inline MT operator *(MT a,MT b)
     25 {
     26     MT c; memset(c.mt,0,sizeof c.mt);
     27     c.x=a.x; c.y=b.y;
     28     for(int i=1;i<=c.x;i++)
     29         for(int j=1;j<=c.y;j++)
     30             for(int k=1;k<=a.y;k++)
     31                 c.mt[i][j]=(c.mt[i][j]+a.mt[i][k]*b.mt[k][j])%mod;
     32     return c;
     33 }
     34 
     35 inline int findfa(int x)
     36 {
     37     if(fa[x]!=x) return fa[x]=findfa(fa[x]);
     38     return fa[x];
     39 }
     40 
     41 inline void check()
     42 {
     43     memset(vis,1,sizeof vis);
     44     for(int i=1;i<=m;i++) fa[i]=i;
     45     for(int i=1;i<m;i++)
     46         for(int j=1;j+i<=m;j++)
     47             if(map[i][j])
     48             {
     49                 if(findfa(i)==findfa(i+j)) return;//判环 
     50                 else fa[findfa(i)]=findfa(i+j);
     51             }
     52     for(int i=1;i<m;i++)
     53         for(int j=1;j+i<=m;j++)
     54             vis[i][i+j]=vis[i+j][i]=!map[i][j];
     55     for(int k=1;k<=m;k++)//传递闭包 
     56         for(int i=1;i<=m;i++)
     57             for(int j=1;j<=m;j++)
     58             {
     59                 if(vis[i][j]==0) continue;
     60                 if(vis[i][k]||vis[k][j]) continue;
     61                 vis[i][j]=0;
     62             }
     63     int tmp=0;
     64     memset(col,-1,sizeof col);
     65     for(int i=1;i<=m;i++)//最小表示法 
     66     {
     67         for(int j=1;j<i;j++)
     68             if(vis[j][i]==0) {col[i]=col[j];break;}
     69         if(col[i]==-1) col[i]=tmp++;
     70     }
     71     tmp=0;
     72     for(int i=1;i<=m;i++) tmp=tmp*10+col[i];
     73     if(hash[tmp]==0)
     74     {
     75         hash[tmp]=++cnt;//cnt个最小表示法 
     76         antihash[cnt]=tmp;
     77     }
     78     ans.mt[hash[tmp]][1]++;//最小表示法代表的方案数 
     79 }
     80 
     81 inline void dfs(int x,int y)
     82 {
     83     if(x==m-1&&y==2) check();
     84     else if(x+y==m+1) dfs(x+1,1);
     85     else
     86     {
     87         map[x][y]=1; dfs(x,y+1);
     88         map[x][y]=0; dfs(x,y+1);
     89     }
     90 }
     91 
     92 inline bool uni()
     93 {
     94     for(int i=2;i<=m;i++)
     95         if(col[1]==col[i]) return 0;
     96     return 1;
     97 }
     98 
     99 inline int trans(int zt)
    100 {
    101     memset(vis,1,sizeof vis);
    102     for(int i=1;i<=m;i++)
    103         for(int j=i+1;j<=m;j++)
    104             if(col[i]==col[j]) vis[i][j]=vis[j][i]=0;
    105     for(int i=1;i<=m;i++)
    106         if(zt&(1<<(m-i))) vis[i][m+1]=vis[m+1][i]=0;
    107     for(int k=1;k<=m+1;k++)//传递闭包 
    108         for(int i=1;i<=m+1;i++)
    109             for(int j=1;j<=m+1;j++)
    110             {
    111                 if(vis[i][j]==0) continue;
    112                 if(vis[i][k]||vis[k][j]) continue;
    113                 vis[i][j]=0;
    114             }
    115     memset(col,-1,sizeof col);
    116     int tmp=0;
    117     for(int i=2;i<=m+1;i++)//最小表示法 
    118     {
    119         for(int j=2;j<i;j++)
    120             if(vis[j][i]==0) {col[i]=col[j];break;}
    121         if(col[i]==-1) col[i]=tmp++;
    122     }
    123     tmp=0;
    124     for(int i=2;i<=m+1;i++) tmp=tmp*10+col[i];
    125     return tmp;
    126 }
    127 
    128 inline int solve(int c,int zt)
    129 {
    130     for(int i=m;i>=1;i--)
    131     {
    132         col[i]=c%10;
    133         c/=10;
    134     }
    135     col[m+1]=-1;
    136     for(int i=1;i<=m;i++)
    137         for(int j=i+1;j<=m;j++)
    138             if(col[i]==col[j]&&(zt&(1<<(m-i)))&&(zt&(1<<(m-j)))) return -1;//
    139     if(!(zt&(1<<(m-1)))&&uni()) return -1;//最左侧的点不连通
    140     return trans(zt);
    141 }
    142 
    143 inline void get_det()//求出转移矩阵 
    144 {
    145     ans.x=cnt; ans.y=1;
    146     zy.x=zy.y=cnt;
    147     for(int i=1;i<=cnt;i++)
    148     {
    149         int lim=1<<m,pa;
    150         for(int j=0;j<lim;j++)
    151         {
    152             pa=solve(antihash[i],j);
    153             if(pa==-1) continue;
    154             zy.mt[hash[pa]][i]++;
    155         }
    156     }
    157 }
    158 
    159 inline void go()
    160 {
    161     scanf("%d%lld",&m,&n);
    162     if(m==1) {puts("1");return;}
    163     dfs(1,1);
    164     get_det();
    165     n-=(long long)m;
    166     while(n)
    167     {
    168         if(n&(1LL)) ans=zy*ans;
    169         zy=zy*zy;
    170         n>>=1LL;
    171     }
    172     printf("%lld\n",ans.mt[hash[0]][1]);
    173 }
    174 
    175 int main()
    176 {
    177     go();
    178     return 0;
    179 }
  • 相关阅读:
    第二章 Centos7下Confluence7.4.0安装
    第一章 APM基本介绍
    第二十一章 MySQL导入数据常见报错解决
    第二十章 Centos7 下 Mysql 8.0.24编译安装
    第一章 Confluence基础介绍
    第十九章 Centos7下 Mysql 8.0.24 二进制安装
    团队项目冲刺阶段一(5)
    团队项目冲刺阶段一(4)
    团队项目冲刺阶段一(3)
    团队项目冲刺阶段一(2)
  • 原文地址:https://www.cnblogs.com/proverbs/p/2914581.html
Copyright © 2011-2022 走看看