zoukankan      html  css  js  c++  java
  • [BZOJ1494][NOI2007]生成树计数 状压dp 并查集

    1494: [NOI2007]生成树计数

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 793  Solved: 451
    [Submit][Status][Discuss]

    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

     

    Source

     
    观察到k很小,n很大。
    考虑状压dp,矩阵快速幂优化。
    但是我们需要对状态进行离散化,还需有一些小技巧,可以看程序。
      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<cstdio>
      5 #include<algorithm>
      6 #include<cmath>
      7 #define maxn 150
      8 #define mod 65521
      9 using namespace std;
     10 int size[10]={1,1,1,3,16,125};
     11 long long n,k;int cnt;
     12 struct data {
     13     long long mat[maxn+1][maxn+1];
     14     data() {memset(mat,0,sizeof(mat));}
     15     data operator *(const data t1) {
     16         data tp;
     17         for(int i=0;i<=cnt;i++)
     18             for(int j=0;j<=cnt;j++)
     19                 for(int k=0;k<=cnt;k++) tp.mat[i][j]+=mat[i][k]*t1.mat[k][j],tp.mat[i][j]%=mod;
     20         return tp;
     21     }
     22 }A,B;
     23 int hash[20000],sta[20000];
     24 int fa[20000];
     25 int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}
     26 void prepare(int pos,int now,int ma) {
     27     if(pos==k+1) {
     28         hash[now]=cnt++;
     29         sta[cnt-1]=now;
     30         return;
     31     }
     32     for(int i=1;i<=ma;i++) prepare(pos+1,now+(i<<(3*(pos-1))),ma+(i==ma));
     33 }
     34 int get() {
     35     int h[200];
     36     memset(h,-1,sizeof(h));
     37     int re=0;
     38     int cc=0;
     39     for(int i=2;i<=k+1;i++) {
     40         if(h[find(i)]==-1) h[find(i)]=++cc;
     41     }
     42     for(int i=2;i<=k+1;i++) {
     43         int now=h[find(i)];
     44         re+=(now<<(3*(i-2)));
     45     }
     46     return hash[re];
     47 }
     48 void build(int x,int add) {
     49     int now=sta[x];
     50     for(int i=1;i<=k+1;i++) fa[i]=i;
     51     for(int i=1;i<=k;i++) {
     52         for(int j=i+1;j<=k;j++) {
     53             if(((now>>((i-1)*3))&7)==((now>>((j-1)*3))&7)) {
     54                 int f1=find(i),f2=find(j);
     55                 if(f1!=f2) fa[f1]=f2;
     56             }
     57         }
     58     }
     59     for(int i=1;i<=k;i++) {
     60         if(add&(1<<(i-1))) {
     61             int f1=find(i),f2=find(k+1);
     62             if(f1==f2) return;
     63             fa[f1]=f2;
     64         }
     65     }
     66     bool flag=0;
     67     for(int i=2;i<=k+1;i++) {
     68         if(find(1)==find(i)) {flag=1;break;}
     69     }
     70     if(!flag) return;
     71     A.mat[get()][x]++;
     72 }
     73 data pow(data x,long long p) {
     74     data ans;
     75     for(int i=0;i<=maxn;i++) ans.mat[i][i]=1;
     76     while(p) {
     77         if(p&1) ans=ans*x;
     78         x=x*x;
     79         p>>=1;
     80          
     81     }
     82     return ans;
     83 }
     84 int main() {
     85     for(int i=0;i<=maxn;i++) B.mat[i][0]=1;
     86     scanf("%lld%lld",&k,&n);
     87     prepare(1,0,1);
     88     for(int i=0;i<cnt;i++)
     89         for(int j=0;j<(1<<k);j++) build(i,j);
     90     /*for(int i=0;i<cnt;i++) {
     91         for(int j=0;j<=k;j++) cout<<A.mat[i][j]<<' ';
     92         cout<<endl;
     93     }*/
     94     for(int i=0;i<cnt;i++) {
     95         int now=sta[i];
     96         int tmp[10]={};
     97         for(int j=1;j<=k;j++) tmp[now>>((j-1)*3)&7]++;
     98         for(int j=1;j<=k;j++) B.mat[i][0]*=size[tmp[j]];
     99     }
    100      
    101     A=pow(A,n-k);
    102     A=A*B;
    103     printf("%lld",A.mat[0][0]%mod);
    104 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    49. 字母异位词分组
    73. 矩阵置零
    Razor语法问题(foreach里面嵌套if)
    多线程问题
    Get json formatted string from web by sending HttpWebRequest and then deserialize it to get needed data
    How to execute tons of tasks parallelly with TPL method?
    How to sort the dictionary by the value field
    How to customize the console applicaton
    What is the difference for delete/truncate/drop
    How to call C/C++ sytle function from C# solution?
  • 原文地址:https://www.cnblogs.com/wls001/p/7992272.html
Copyright © 2011-2022 走看看