坑了好多天的题,终于补上了

首先发现 \(i\) 这个点和 \(i-k\) 之前的点没有边,所以 \(i-k\) 之前的点肯定联通,只要处理中间 \(k\) 个点的联通状态就好了。我们用最小表示法,\(f[i]\) 表示最小的与 \(i\) 联通的点编号,发现状态最多有52种,然后枚举下一个点与那些点之间连边,得到转移方程,矩阵快速幂优化转移即可

(反正怎么说估计都听不懂,还是贴代码比较靠谱)

#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<long long,long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
#define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--) ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
} const int mod=65521; ll n,k;
int tot,f[20],sta[100][20],a[20],cnt[100],num[20],edge[20]; struct Matrix{
int mat[60][60];
Matrix(int x){
memset(mat,0,sizeof(mat));
if(x) rep(i,1,tot) mat[i][i]=1;
}
Matrix operator*(Matrix ano){
Matrix ret(0);
rep(i,1,tot)
rep(j,1,tot)
rep(k,1,tot)
ret.mat[i][j]=(ret.mat[i][j]+mat[i][k]*1ll*ano.mat[k][j])%mod;
return ret;
}
Matrix operator^(ll k){
Matrix ret(1),xx(0);
memcpy(xx.mat,mat,sizeof(mat));
while(k){
if(k&1) ret=ret*xx;
xx=xx*xx;k>>=1;
}
return ret;
}
void pr(){
rep(i,1,tot){
rep(j,1,tot){
printf("%d ",mat[i][j]);
}
puts("");
}
puts("");
}
} trans(0); int ksm(int x,int p){
int ret=1;
while(p){
if(p&1) ret=ret*x;
x=x*x;
p>>=1;
}
return ret;
}
//处理当前状态的生成树个数
//公式 大小为n的完全图生成树个数为n^(n-2)
void calc(int x){
memset(f,0,sizeof(f));cnt[x]=1;
rep(i,1,k) f[sta[x][i]]++;
for(int i=1;f[i];i++) if(f[i]>2) cnt[x]*=ksm(f[i],f[i]-2);
}
//前x个分成了s个联通块的方案
void dfs1(int x,int s){
if(x==k+1){
tot++;
rep(i,1,k) sta[tot][i]=a[i];
calc(tot);return;
}
for(int i=1;i<=s+1;i++) a[x]=i,dfs1(x+1,max(i,s));
} inline bool issame(int x[],int b[]){
rep(i,1,k) if(x[i]!=b[i]) return 0;
return 1;
}
//求此时的状态是什么
inline void get1(int id){
memcpy(a,sta[id],sizeof(a));
rep(i,1,k){
if(edge[i]){
if(!a[k+1]) a[k+1]=a[i];
else{
int x=a[i];
rep(j,1,k) if(a[j]==x) a[j]=a[k+1];
}
}
}
rep(i,1,k) a[i]=a[i+1];
memset(num,0,sizeof(num));int num1=0;
rep(i,1,k){
if(!num[a[i]]) num[a[i]]=++num1;
a[i]=num[a[i]];
}
rep(i,1,tot) if(issame(a,sta[i])){
trans.mat[id][i]++;
return;
}
}
//求id能够转移到什么状态
void dfs2(int id,int x){
if(x==k+1){
get1(id);return;
}
dfs2(id,x+1); //不连k+1到x的边
if(!f[sta[id][x]]){ //k+1到这个联通块目前没有边,可以连
//连k+1到x的边
f[sta[id][x]]=1;edge[x]=1;
dfs2(id,x+1);
f[sta[id][x]]=0;edge[x]=0;
}
} int main(){
k=read(),n=read();
dfs1(1,0);
//处理转移
rep(i,1,tot){
memset(f,0,sizeof(f));
memset(edge,0,sizeof(edge));
bool flag=1;
rep(j,2,k) if(sta[i][j]==1){
flag=0;break;
}
if(flag){
//没有出现过与1相连的边,所以下一条边必须和1相连
f[1]=1;edge[1]=1;dfs2(i,2);
}
else dfs2(i,1);
}
trans=trans^(n-k);
ll ans=0;
rep(i,1,tot) ans=(ans+trans.mat[i][1]*1ll*cnt[i])%mod;
printf("%lld\n",ans);
return 0;
}

bzoj 1494 生成树计数的更多相关文章

  1. BZOJ 1494 生成树计数(生成树计数-矩阵)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1494 题意: 思路: int SIZE; struct matrix { i64 a[N] ...

  2. BZOJ 1016 生成树计数

    现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的最小生成树 ...

  3. BZOJ 1002 生成树计数&高精度

    给你定义一种特殊的图 这种图总共有n个节点 假设编号为0~n-1 首先1~n-1排成环形 每个点与相邻的两个点有边 其次这n-1个节点每个和0节点有一条边 每次询问你一个n 要回到当前n节点的特殊图有 ...

  4. BZOJ1494 [NOI2007]生成树计数

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

  5. [BZOJ1494][NOI2007]生成树计数 状压dp 并查集

    1494: [NOI2007]生成树计数 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 793  Solved: 451[Submit][Status][ ...

  6. @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列

    目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...

  7. 【BZOJ1002】【FJOI2007】轮状病毒(生成树计数)

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1766  Solved: 946[Submit][Status ...

  8. SPOJ 104 HIGH - Highways 生成树计数

    题目链接:https://vjudge.net/problem/SPOJ-HIGH 解法: 生成树计数 1.构造 基尔霍夫矩阵(又叫拉普拉斯矩阵) n阶矩阵 若u.v之间有边相连 C[u][v]=C[ ...

  9. Luogu P5296 [北京省选集训2019]生成树计数

    Luogu P5296 [北京省选集训2019]生成树计数 题目链接 题目大意:给定每条边的边权.一颗生成树的权值为边权和的\(k\)次方.求出所有生成树的权值和. 我们列出答案的式子: 设\(E\) ...

随机推荐

  1. [usaco2008feb_gold]路面修整

      FJ打算好好修一下农场中某条凹凸不平的土路.按奶牛们的要求,修好后的路面高度应当单调上升或单调下降,也就是说,高度上升与高度下降的路段不能同时出现在修好的路中. 整条路被分成了N段,N个整数A_1 ...

  2. MongoDB 项目集成 mongo-driver 3.4.2

    第一次写技术!大白话讲讲.拿着用就可以了 本人是,NET的技术人员,会点JAVA所以很多不专业,见谅哈 刚刚开始使用mongo 整整搞了两天我才搞个半桶水,还是将就着用吧 随便把mongo在win的搭 ...

  3. mycat的事务支持情况

    中秋国庆一共12天,玩的有点嗨,完全没想工作的事情- -.回来赶紧补补.看了一下mycat关于事务的支持情况,做一下记录. 说mycat的事务支持之前,先说说XA协议,即分布式事务.指的是TM(事务管 ...

  4. codeforces 702C C. Cellular Network(水题)

    题目链接: C. Cellular Network time limit per test 3 seconds memory limit per test 256 megabytes input st ...

  5. java第五天之---方法与数组

    案例一:从键盘输入两个数据,比较大小 import java.util.Scanner;class FunctionTest { public static void main(String[] ar ...

  6. Ubuntu16.04 安装cuda9.0 cudnn 7.0.5

    参考网址:https://blog.csdn.net/zhuangwu116/article/details/81063234 (1)下载安装文件: 下载cuda9.0 runfile 文件 下载地址 ...

  7. tetrahedron

    题意: 求解一个四面体的内切球. 解法: 首先假设内切球球心为$(x0,x1,x2)$,可以用$r = \frac{3V}{S_1+S_2+S_3+S_4}$得出半径, 这样对于四个平面列出三个方程, ...

  8. rpm 命令|rpm 安装|rpm 卸载|rpm 使用|rpm 删除

    在Linux操作系统中,有一个系统软件包,它的功能类似于Windows里面的“添加/删除程序”,但是功能又比“添加/删除程序”强很多,它就是Red Hat Package Manager(简称RPM) ...

  9. C++多态性:虚函数的调用原理

    多态性给我们带来了好处:多态使得我们可以通过基类的引用或指针来指明一个对象(包含其派生类的对象),当调用函数时可以自动判断调用的是哪个对象的函数. 一个函数说明为虚函数,表明在继承的类中重载这个函数时 ...

  10. 制作Docker镜像的两种方式

    此文已由作者朱笑天授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 一.使用docker commit命令制作docker镜像 1. pull一个centos6.6的基础镜像, ...