BZOJ1494 [NOI2007]生成树计数
题意
| F.A.Qs | Home | Discuss | ProblemSet | Status | Ranklist | Contest | 入门OJ | ModifyUser autoint | Logout | 捐赠本站 |
|---|
Problem 1494. -- [NOI2007]生成树计数
1494: [NOI2007]生成树计数
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 1024 Solved: 592
[Submit][Status][Discuss]
Description
.png)

.png)
.png)
.png)

.png)
.png)
Input
包含两个整数k,n,由一个空格分隔。k表示要将所有距离不超过k(含k)的结点连接起来,n表示有n个结点。
Output
输出一个整数,表示生成树的个数。由于答案可能比较大,所以你 只要输出答案除65521 的余数即可。
Sample Input
Sample Output
HINT

Source
[Submit][Status][Discuss]
HOME
Back
中文
فارسی
English
ไทย
分析
参照xyz32768的题解。
定义状态: \(f[i][S]\)表示\(i\)个点的图,编号差\(≤k\)的点对之间有连边,现选出一些边,连通第\(1\)个点到第\(i−k\)个点,第\(i−k+1\)个点到第\(i\)个点的连通性为\(S\),第\(i−k+1\)个点到第\(i\)个点至少存在一点与前\(i−1\)个点连通,且选出的边无环的方案数。
注意这里的\(S\)压缩连通性使用的是最小表示法: 对连通块进行标号,从\(1\)到连通块个数,首次出现位置越靠前的连通块编号越小。
会发现有效\(S\)的个数是贝尔数,即第二类斯特林数的前缀和。 \(k=5\)时状态数只有\(52\) 。
如何求\(f[i+1][T]\)从\(f[i][S]\)的转移系数呢?
我们可以对于一个\(S\),\(2^k\)枚举第\(i−k+1\)个点到第\(i\)个点是否与\(i+1\)连边,大力计算即可。
但要注意:
- 如果第\(i−k+1\)个点在第\(i−k+1\)到第\(i\)个点中单独属于一个连通块,那么\(i−k+1\)和\(i+1\)间必须连边,否则不能保证「连通前\(i−k+1\)个点」。
- 不能由\(i\)连向第\(i−k+1\)个点到第\(i\)个点中的同一个连通块,否则会形成环。
发现转移系数不变且为一阶,因此直接上矩阵快速幂。
代码
参照Icefox_zhx的代码。dfs写有许多好处。
我们可以先用一个DFS预处理出所有可能出现的连通性的状态。然后再枚举连通性状态S以及下一个点和S里的K个点中的哪些点连边,再判断从连通性状态S转移出来的新状态S′是否是合法的,若合法,在邻接矩阵里,标记从S到S′的方案数加1.
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
co int M=7,N=60,mod=65521;
int m;ll n;
int temp[M],sta[N][M],tot,ini[N];
void init_sta(int id){ //预处理所有状态的初始种类数
static int cnt[M];
memset(cnt,0,sizeof cnt);
for(int i=1;i<=m;++i) ++cnt[sta[id][i]];
ini[id]=1;
for(int i=1;cnt[i];++i)if(cnt[i]>2) ini[id]*=pow(cnt[i],cnt[i]-2);
//n个点的完全图的生成树个数为n^(n-2)个
}
void dfs_sta(int i,int x){ //前i-1个点分成了x个连通块
if(i==m+1) return memcpy(sta[++tot],temp,sizeof temp),init_sta(tot);
for(int j=1;j<=x+1;++j) temp[i]=j,dfs_sta(i+1,max(j,x));
}
struct matrix{
int a[N][N];
il int*operator[](int x){return a[x];}
il co int*operator[](int x)co{return a[x];}
matrix operator*(co matrix&b)co{
matrix c;
memset(c.a,0,sizeof c.a);
for(int i=1;i<=tot;++i)
for(int j=1;j<=tot;++j)
for(int k=1;k<=tot;++k)
c[i][j]=(c[i][j]+(ll)a[i][k]*b[k][j])%mod;
return c;
}
matrix operator^(ll k){
matrix x=*this,re;
memset(re.a,0,sizeof re.a);
for(int i=1;i<=tot;++i) re[i][i]=1;
for(;k;k>>=1,x=x*x)
if(k&1) re=re*x;
return re;
}
}trans;
bool f[M],edge[M]; //f[i]:i连通块是否已连过,edge[i]:i位置是否连边了
bool issame(int a[],int b[]){
for(int i=1;i<=m;++i)
if(a[i]!=b[i]) return 0;
return 1;
}
void get_tra(int id){ //求sta[id]此时转移到的状态a
static int a[M];
memcpy(a,sta[id],sizeof a);
for(int i=1;i<=m;++i)if(edge[i]){
if(a[m+1]==0) a[m+1]=a[i];
else for(int x=a[i],j=1;j<=m;++j)if(a[j]==x) a[j]=a[m+1];
}
for(int i=1;i<=m;++i) a[i]=a[i+1]; //把状态往前挪一个
static int num[M],cnt;
memset(num,0,sizeof num),cnt=0;
for(int i=1;i<=m;++i){ //重新标号,使得满足最小表示法
if(!num[a[i]]) num[a[i]]=++cnt;
a[i]=num[a[i]];
}
for(int i=1;i<=tot;++i)if(issame(a,sta[i]))
return ++trans[id][i],void();
}
void dfs_tra(int id,int i){
if(i==m+1) return get_tra(id);
dfs_tra(id,i+1);
if(!f[sta[id][i]]){
f[sta[id][i]]=1,edge[i]=1;
dfs_tra(id,i+1);
f[sta[id][i]]=0,edge[i]=0;
}
}
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
read(m),read(n);
dfs_sta(1,0); //预处理出k个点的所有连接状态,用最小表示法表示,以及每种状态的初始种类数
for(int i=1;i<=tot;++i){
memset(f,0,sizeof f);
memset(edge,0,sizeof edge);
bool flag=1;
for(int j=2;j<=m;++j)
if(sta[i][j]==1) {flag=0;break;}
if(flag) f[1]=1,edge[1]=1,dfs_tra(i,2); //1必须连这个了。
else dfs_tra(i,1);
}
trans=trans^(n-m);
int ans=0;
for(int i=1;i<=tot;++i) ans=(ans+(ll)trans[i][1]*ini[i])%mod;
printf("%d\n",ans);
return 0;
}
BZOJ1494 [NOI2007]生成树计数的更多相关文章
- [BZOJ1494][NOI2007]生成树计数 状压dp 并查集
1494: [NOI2007]生成树计数 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 793 Solved: 451[Submit][Status][ ...
- [NOI2007]生成树计数环形版
NOI2007这道题人类进化更完全之后出现了新的做法 毕姥爷题解: 于是毕姥爷出了一道环形版的这题(test0814),让我们写这个做法 环形的情况下,k=5的时候是162阶递推. 求这个递推可以用B ...
- NOI2007 生成树计数
题目 首先我要吐槽,这题目就是坑,给那么多无用的信息,我还以为要根据提示才能做出来呢! 算法1 暴力,傻傻地跟着提示,纯暴力\(40\)分,高斯消元\(60\)分. 算法2 DP!一个显然的东西是,这 ...
- [BZOJ1494]生成树计数
[BZOJ1494] [NOI2007]生成树计数 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现:·n个结点的环的生成树个数为n.·n个结点的完全图的生成树 ...
- 【BZOJ1494】【NOI2007】生成树计数(动态规划,矩阵快速幂)
[BZOJ1494][NOI2007]生成树计数(动态规划,矩阵快速幂) 题面 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现: ·n个结点的环的生成树个数为 ...
- 【BZOJ1002】【FJOI2007】轮状病毒(生成树计数)
1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1766 Solved: 946[Submit][Status ...
- SPOJ 104 HIGH - Highways 生成树计数
题目链接:https://vjudge.net/problem/SPOJ-HIGH 解法: 生成树计数 1.构造 基尔霍夫矩阵(又叫拉普拉斯矩阵) n阶矩阵 若u.v之间有边相连 C[u][v]=C[ ...
- Luogu P5296 [北京省选集训2019]生成树计数
Luogu P5296 [北京省选集训2019]生成树计数 题目链接 题目大意:给定每条边的边权.一颗生成树的权值为边权和的\(k\)次方.求出所有生成树的权值和. 我们列出答案的式子: 设\(E\) ...
- Loj 2320.「清华集训 2017」生成树计数
Loj 2320.「清华集训 2017」生成树计数 题目描述 在一个 \(s\) 个点的图中,存在 \(s-n\) 条边,使图中形成了 \(n\) 个连通块,第 \(i\) 个连通块中有 \(a_i\ ...
随机推荐
- mysql插入中文乱码
https://www.cnblogs.com/zhchoutai/p/7364835.html 最简单的一招,不用修改my.ini文件: 1.停掉mysql服务 2.启动:X:\%path%\MyS ...
- Mybatis的二级缓存注意点
--声明:一下内容都不一定是正确的,只是自己测试的结果,请自己的动手操作得出自己的结论 1.开启Mybatis的二级缓存,不仅要在SqlMapConfig.xml中进行开启总开关,还要在对应的XXXM ...
- [Leetcode 3] 最长不重复子串 Longest substring without repeating 滑动窗口
[题目] Given a string, find the length of the longest substring without repeating characters. [举例] Exa ...
- VSTO:使用C#开发Excel、Word【3】
<Visual Studio Tools for Office: Using C# with Excel, Word, Outlook, and InfoPath >——By Eric C ...
- tfs 2017 使用
安装完成之后,创建一个项目管理. 初始化代码库 然后下载代理 (服务器)并设置.下载代理需要FQ才可以下载成功. 想要支持 netcore2.0 必须在代理服务器上安装 vs2017 跟netcor ...
- 无法获取 vmci 驱动程序版本: 句柄无效
https://jingyan.baidu.com/article/a3a3f811ea5d2a8da2eb8aa1.html 将 vmci0.present = "TURE" 改 ...
- DevExpress v18.1新版亮点——DevExtreme篇(一)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExtreme JavaScript Controls v18.1 的新功能 ...
- 关于这次安装Oracle
前后大概经历了一个星期,今天下午(先是用的Navicat)当我尝试性的把用户名上方的复选项从服务名换成SID时,竟然瞬间连接成功了,整个人都是蒙B的,这样就好了? 之后我又用PLsql测试了一下,秒进 ...
- 合并k个有序数组
给定K个有序数组,每个数组有n个元素,想把这些数组合并成一个有序数组 可以利用最小堆完成,时间复杂度是O(nklogk),具体过程如下: 创建一个大小为n*k的数组保存最后的结果创建一个大小为k的最小 ...
- day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
# 多态的理解:# Python 天生自带多态# 鸭子类型 list 和 tuple 就是一对鸭子类型 很像但是没有继承关系## 而其他的类型 上传参数或者打印参数的时候 必须是指定的数据类型# -- ...