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,矩阵快速幂优化。
但是我们需要对状态进行离散化,还需有一些小技巧,可以看程序。
 #include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define maxn 150
#define mod 65521
using namespace std;
int size[]={,,,,,};
long long n,k;int cnt;
struct data {
long long mat[maxn+][maxn+];
data() {memset(mat,,sizeof(mat));}
data operator *(const data t1) {
data tp;
for(int i=;i<=cnt;i++)
for(int j=;j<=cnt;j++)
for(int k=;k<=cnt;k++) tp.mat[i][j]+=mat[i][k]*t1.mat[k][j],tp.mat[i][j]%=mod;
return tp;
}
}A,B;
int hash[],sta[];
int fa[];
int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}
void prepare(int pos,int now,int ma) {
if(pos==k+) {
hash[now]=cnt++;
sta[cnt-]=now;
return;
}
for(int i=;i<=ma;i++) prepare(pos+,now+(i<<(*(pos-))),ma+(i==ma));
}
int get() {
int h[];
memset(h,-,sizeof(h));
int re=;
int cc=;
for(int i=;i<=k+;i++) {
if(h[find(i)]==-) h[find(i)]=++cc;
}
for(int i=;i<=k+;i++) {
int now=h[find(i)];
re+=(now<<(*(i-)));
}
return hash[re];
}
void build(int x,int add) {
int now=sta[x];
for(int i=;i<=k+;i++) fa[i]=i;
for(int i=;i<=k;i++) {
for(int j=i+;j<=k;j++) {
if(((now>>((i-)*))&)==((now>>((j-)*))&)) {
int f1=find(i),f2=find(j);
if(f1!=f2) fa[f1]=f2;
}
}
}
for(int i=;i<=k;i++) {
if(add&(<<(i-))) {
int f1=find(i),f2=find(k+);
if(f1==f2) return;
fa[f1]=f2;
}
}
bool flag=;
for(int i=;i<=k+;i++) {
if(find()==find(i)) {flag=;break;}
}
if(!flag) return;
A.mat[get()][x]++;
}
data pow(data x,long long p) {
data ans;
for(int i=;i<=maxn;i++) ans.mat[i][i]=;
while(p) {
if(p&) ans=ans*x;
x=x*x;
p>>=; }
return ans;
}
int main() {
for(int i=;i<=maxn;i++) B.mat[i][]=;
scanf("%lld%lld",&k,&n);
prepare(,,);
for(int i=;i<cnt;i++)
for(int j=;j<(<<k);j++) build(i,j);
/*for(int i=0;i<cnt;i++) {
for(int j=0;j<=k;j++) cout<<A.mat[i][j]<<' ';
cout<<endl;
}*/
for(int i=;i<cnt;i++) {
int now=sta[i];
int tmp[]={};
for(int j=;j<=k;j++) tmp[now>>((j-)*)&]++;
for(int j=;j<=k;j++) B.mat[i][]*=size[tmp[j]];
} A=pow(A,n-k);
A=A*B;
printf("%lld",A.mat[][]%mod);
}

[BZOJ1494][NOI2007]生成树计数 状压dp 并查集的更多相关文章

  1. HDU5117 Fluorescent 期望 计数 状压dp 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/HDU5117.html 题目传送门 - HDU5117 题意 $T$ 组数据. 给你 $n$ 盏灯 ,$m$ 个 ...

  2. BZOJ1494 [NOI2007]生成树计数

    题意 F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser  autoint Logout 捐赠本站 Probl ...

  3. CCPC-Wannafly Winter Camp Day3 Div1 - 精简改良 - [生成树][状压DP]

    题目链接:https://zhixincode.com/contest/14/problem/D?problem_id=206 样例输入 1  5 5 1 2 1 1 3 1 2 4 1 2 5 1 ...

  4. hdu5304 Eastest Magical Day Seep Group&#39;s Summer 状压dp+生成树

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5304 16个点的无向图,问能生成多少个n条边的连通图.(即多一条边的树) 先n^3 * 2^n 枚举全部的 ...

  5. 状态压缩动态规划 状压DP

    总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...

  6. AGC 016 F - Games on DAG(状压dp)

    题意 给你一个有 \(n\) 个点 \(m\) 条边 DAG 图,点的标号和拓扑序一致. 现在有两个人进行博弈,有两个棋子分别在 \(1, 2\) 号点上,需要不断移动到它指向的点上. 如果当前两个点 ...

  7. P1879 [USACO06NOV]玉米田Corn Fields 状压dp/插头dp

    正解:状压dp/插头dp 解题报告: 链接! ……我真的太菜了……我以为一个小时前要搞完的题目调错误调了一个小时……90分到100我差不多搞了一个小时…… 然后这题还是做过的……就很气,觉得确实是要搞 ...

  8. BZOJ.3058.四叶草魔杖(Kruskal 状压DP)

    题目链接 \(2^{16}=65536\),可以想到状压DP.但是又有\(\sum A_i\neq 0\)的问题.. 但是\(2^n\)这么小,完全可以枚举所有子集找到\(\sum A_i=0\)的, ...

  9. 【ZJOI2017 Round1练习&BZOJ4774】D3T2 road(斯坦纳树,状压DP)

    题意: 对于边带权的无向图 G = (V, E),请选择一些边, 使得1<=i<=d,i号节点和 n − i + 1 号节点可以通过选中的边连通, 最小化选中的所有边的权值和. d< ...

随机推荐

  1. hdu2421(数学,因式分解素数筛)

    Xiaoming has just come up with a new way for encryption, by calculating the key from a publicly view ...

  2. (转)MongoDB numa系列问题三:overcommit_memory和zone_reclaim_mode

    内核参数overcommit_memory : 它是 内存分配策略 可选值:0.1.2.0:表示内核将检查是否有足够的可用内存供应用进程使用:如果有足够的可用内存,内存申请允许:否则,内存申请失败,并 ...

  3. jloi2017(shoi2017?)六省联考酱油记

    Day -n 听说了4.22.4.23的省选,而且还是六省联考. 压力山大. 尽管我只是一名高一的simple OIer,在省选到来之前,心里还是很紧张的. 毕竟自己也知道南方dalao们都是神犇,像 ...

  4. SRM710 div1 MagicNim(博弈论)

    题目大意: 给出n+1堆石子,前n堆石子的数量是a[i],最后一堆只有1个石子,但是具有魔力 拿走该石子的一方可以选择接下来是进行普通的Nim游戏还是anti-nim游戏 问是先手必胜还是必败 首先拿 ...

  5. [洛谷P1251]餐巾计划问题

    题目大意:一个餐厅N天,每天需要$r_i$块餐巾.每块餐巾需要p元,每天用过的餐巾变脏,不能直接用.现在有快洗店和慢洗店,快洗店洗餐巾需要m天,每块花费f元:慢洗店洗餐巾需要n天,每块餐巾s元(m & ...

  6. Boosting&Bagging

    Boosting&Bagging 集成学习方法不是单独的一个机器学习算法,而是通过构建多个机器学习算法来达到一个强学习器.集成学习可以用来进行分类,回归,特征选取和异常点检测等.随机森林算法就 ...

  7. Acunetix Web Vulnarability Scanner V10.5 详细中文手册

    目录: 0×00.什么是Acunetix Web Vulnarability Scanner ( What is AWVS?) 0×01.AWVS安装过程.主要文件介绍.界面简介.主要操作区域简介(I ...

  8. hdu Shell Necklace 5730 分治FFT

    Description Perhaps the sea‘s definition of a shell is the pearl. However, in my view, a shell neckl ...

  9. 入门级:GitHub和Git超超超详细使用教程!

    GitHub和Git入门 考虑到大家以前可能对版本控制工具和Linux命令行工具都不了解,我写了一个简单的博客来让大家学会入门使用方法. GitHub的简单使用 第一步 创建GitHub账号 1. 打 ...

  10. HDU 5685 Problem A | 快速幂+逆元

    Problem A Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...