zoukankan      html  css  js  c++  java
  • [NOI2007]生成树计数

    Description

    最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现:
    ·n个结点的环的生成树个数为n。
    ·n个结点的完全图的生成树个数为n^(n-2)。这两个发现让小栋欣喜若狂,由此更加坚定了他继续计算生成树个数的
    想法,他要计算出各种各样图的生成树数目。一天,小栋和同学聚会,大家围坐在一张大圆桌周围。小栋看了看,
    马上想到了生成树问题。如果把每个同学看成一个结点,邻座(结点间距离为1)的同学间连一条边,就变成了一
    个环。可是,小栋对环的计数已经十分娴熟且不再感兴趣。于是,小栋又把图变了一下:不仅把邻座的同学之间连
    一条边,还把相隔一个座位(结点间距离为2)的同学之间也连一条边,将结点间有边直接相连的这两种情况统称
    为有边相连,如图1所示。
    小栋以前没有计算过这类图的生成树个数,但是,他想起了老师讲过的计算任意图的生成树个数的一种通用方法:
    构造一个n×n的矩阵A={aij},其中
    其中di表示结点i的度数。与图1相应的A矩阵如下所示。为了计算图1所对应的生成数的个数,只要去掉矩阵A的最
    后一行和最后一列,得到一个(n-1)×(n-1)的矩阵B,计算出矩阵B的行列式的值便可得到图1的生成树的个数所以
    生成树的个数为|B|=3528。小栋发现利用通用方法,因计算过于复杂而很难算出来,而且用其他方法也难以找到更
    简便的公式进行计算。于是,他将图做了简化,从一个地方将圆桌断开,这样所有的同学形成了一条链,连接距离
    为1和距离为2的点。例如八个点的情形如下:
    这样生成树的总数就减少了很多。小栋不停的思考,一直到聚会结束,终于找到了一种快捷的方法计算出这个图的
    生成树个数。可是,如果把距离为3的点也连起来,小栋就不知道如何快捷计算了。现在,请你帮助小栋计算这类
    图的生成树的数目。

    Input

    包含两个整数k,n,由一个空格分隔。k表示要将所有距离不超过k(含k)的结点连接起来,n表示有n个结点。

    Output

    输出一个整数,表示生成树的个数。由于答案可能比较大,所以你 只要输出答案除65521 的余数即可。

    Sample Input

    3 5

    Sample Output

    75

    HINT

    因为k很小,所以考虑状态压缩

    每一个状态表示i的前k个点各自属于哪个连通块

    用一个k位的k进制数表示状态

    然而状态很多,用最小表示法

    即122与233是等价的

    这样状态数不超过52

    然后就可以DP

    $f[i][S]=sum_{S_last}f[i-1][S_last]$

    显然可以用矩阵快速幂

    实现枚举S,找到通过变换能形成的所有状态

    具体通过一个二进制数,表示第k+1个点向哪些点连边

    用并查集判断,并将新的状态改为最小表示

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 lol cnt,n,Mod=65521,k,id[100001],vis[201],set[201];
      9 lol h[201],v[201];
     10 struct Matrix
     11 {
     12   lol a[201][201];
     13   Matrix operator * (const Matrix &x) const
     14   {
     15     Matrix res;
     16     memset(res.a,0,sizeof(res.a));
     17     for(int i=1;i<=cnt;++i)
     18       for(int j=1;j<=cnt;++j)
     19         for(int k=1;k<=cnt;++k)
     20         res.a[i][j]=(res.a[i][j]+(a[i][k]*x.a[k][j])%Mod)%Mod;
     21     return res;
     22   }
     23 }ans,Mat;
     24 int find(int x)
     25 {
     26   if (set[x]!=x) set[x]=find(set[x]);
     27   return set[x];
     28 }
     29 lol pow(lol x,lol y)
     30 {
     31   lol res=1;
     32   while (y)
     33     {
     34       if (y&1) res=res*x%Mod;
     35       x=x*x%Mod;
     36       y>>=1;
     37     }
     38   return res;
     39 }
     40 Matrix qpow(lol y)
     41 {int i;
     42   Matrix res;
     43   memset(res.a,0,sizeof(res.a));
     44   for (i=1;i<=cnt;i++)
     45     res.a[i][i]=1;
     46   while (y)
     47     {
     48       if (y&1) res=res*Mat;
     49       Mat=Mat*Mat;
     50       y>>=1;
     51     }
     52   return res;
     53 }
     54 void dfs(int x,int ed,int S)
     55 {int i;
     56   if (x==k+1)
     57     {
     58       id[S]=++cnt;
     59       h[cnt]=S;
     60       return;
     61     }
     62   for (i=1;i<=ed;i++)
     63     dfs(x+1,ed+(i==ed),(i<<(3*(x-1)))+S);
     64 }
     65 int get_id()
     66 {
     67   memset(vis,-1,sizeof(vis));
     68   int cc=0,i;
     69   for (i=2;i<=k+1;i++)
     70     if (vis[find(i)]==-1) vis[find(i)]=++cc;
     71   int x=0;
     72   for (i=2;i<=k+1;i++)
     73     {
     74       x+=(vis[find(i)]<<(3*(i-2)));
     75     }
     76   return id[x];
     77 }
     78 void build_Mat(int now,int add)
     79 {int i,j,flag;
     80   for (i=0;i<=k+1;i++)
     81     set[i]=i;
     82   for (i=1;i<=k;i++)
     83     {
     84       for (j=i+1;j<=k;j++)
     85     if ((now>>((i-1)*3)&7)==(now>>((j-1)*3)&7))
     86     {
     87       int p=find(i),q=find(j);
     88       if (p!=q) set[p]=q;
     89     }
     90     }
     91   for (i=1;i<=k;i++)
     92     if (add&(1<<i-1))
     93       {
     94     int p=find(i),q=find(k+1);
     95     if (p==q) return;
     96     set[p]=q;
     97       }
     98   flag=0;
     99   for (i=2;i<=k+1;i++)
    100     {
    101       if (find(1)==find(i)) {flag=1;break;}
    102     }
    103   if (!flag) return;
    104   Mat.a[id[now]][get_id()]++;
    105 }
    106 int main()
    107 {int i,j;
    108   cin>>k>>n;
    109   dfs(1,1,0);
    110   for (i=1;i<=cnt;i++)
    111     {
    112       for (j=0;j<(1<<k);j++)
    113     {
    114       build_Mat(h[i],j);
    115     }
    116     }
    117   for (i=1;i<=cnt;i++)
    118     {
    119       memset(v,0,sizeof(v));
    120       int x=h[i];
    121       int as=1;
    122       for (j=1;j<=k;j++)
    123     {
    124       v[x>>(3*(j-1))&7]++;
    125     }
    126       for (j=1;j<=k;j++)
    127     if (v[j]>=2)
    128     {
    129       as*=pow(v[j],v[j]-2);
    130     }
    131       ans.a[1][i]=as;
    132     }
    133   ans=ans*qpow(n-k);
    134   cout<<ans.a[1][1]<<endl;
    135 }
  • 相关阅读:
    android和ios系统框架
    iOS分类和扩展(Categories和Extensions)
    iOS并发编程
    认识View Controller
    JVM(Java虚拟机)
    iOS Apps核心对象
    Memory Management in Cocoa Program
    Block和GCD介绍
    iOS 系统框架分层结构
    ReLearn C(The C Programming Language.2Nd)
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8598844.html
Copyright © 2011-2022 走看看