【矩阵乘法】生成树计数(luogu 2109/NOI 2007)
生成树计数
luogu 2109
题目大意
有n个排成一列的点,把距离不超过k的点之间连边,问这个图的生成树个数
输入样例
3 5
输出样例
75
样例说明
样例对应的图如下:
数据范围
解题思路
因为n十分大,不能直接2^m暴力枚举(m为总边数)
k十分小,可以从k入手
考虑到对某个点有贡献的只有前k个点
我们可以设状态表示前k个点的连接情况(即那几个点连在了一起)
状态如果直接用k位数表示肯定不行
考虑除掉无用状态
对于着k个数,如果前面有和它相连的点,那么这个点的数值等于和它相连的点的数值,如果没有,则它的数值等于前k个数中最大数值+1
例如:
k=5,1和3相连,2和5相连
则表示出来的状态为12132
s1=++ws_1=++ws1=++w
s2=++ws_2=++ws2=++w
s3=s1s_3=s_1s3=s1
s4=++ws_4=++ws4=++w
s5=s2s_5=s_2s5=s2
得出状态后,我们输出总装台数,k=5时竟只有52种!
用一个数组给各个状态存一下新的编号(52种中的第几种)
然后考虑状态之间的转移
对于所有用的状态,2k2^k2k枚举第k+1k+1k+1个点和kkk个点是否连边
使其满足以下条件
1.不连成环(即数值相同的点最多连一个,不然会形成环)
2.保证第1个点要和2∼k+12\sim k+12∼k+1个点中的一个相连(要么和k+1k+1k+1相连,要么和2∼k2\sim k2∼k个点中某个点的数值相等)
得出状态后通过前面的计算方法,把新状态的编号求出来,然后在矩阵中连起来
得到转移矩阵后,就可以用矩阵乘法快速得出n个点的结果了
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define wyc 65521
using namespace std;
ll n, k, w, ww, s[10], ss[10], fa[10], p[100000];
struct matrix
{ll n, m, a[100][100];matrix operator *(const matrix &b) const{matrix c;c.n = n;c.m = b.m;for (int i = 1; i <= c.n; ++i)for (int j = 1; j <= c.m; ++j)c.a[i][j] = 0;for (int i = 1; i <= c.n; ++i)for (int k = 1; k <= m; ++k)for (int j = 1; j <= c.m; ++j)c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j] % wyc) % wyc;return c;}
}A, B;
void dfs1(ll x, ll y, ll z)
{if (x > k){p[z] = ++w;//新编号ll num = 1, g = 0;for (int i = 1; i <= k; ++i){g = 1;for (int j = 1; j <= s[i] - 2; ++j)//题目说明中n个点的完全图生成树个数为n^(n-2)g = g * s[i];num = num * g;//各种种数相乘}A.a[1][w] = num;//计入初始矩阵return;}for (int i = 1; i <= y; ++i){s[i]++;//这个数值的数+1dfs1(x + 1, y, z * 10 + i);//和前面已有的点相连s[i]--;}s[y + 1]++;//新的数值dfs1(x + 1, y + 1, z * 10 + y + 1);//不相连s[y + 1]--;return;
}
ll find(ll x)
{return x == fa[x]?x:find(fa[x]);//并查集
}
void pp(ll x, ll y)
{if (x > k){ll num = 0, ww = 0;memset(ss, 0, sizeof(ss));for (int i = 2; i <= k + 1; ++i){ll g = find(i);if (!ss[g]) ss[g] = ++ww;//没有相连的就新加一个数值num = num * 10 + ss[g];//用十进制存起来}if (ss[find(1)]) B.a[p[y]][p[num]]++;//第一个数有被加到,那就连接状态return;}ll g = find(k + 1), gg = find(x);if (gg != g)//暂未相连{fa[g] = gg;//连接pp(x + 1, y);fa[g] = g;//没有路径压缩所以可拆边}pp(x + 1, y);//不练的情况return;
}
void dfs2(ll x, ll y, ll z)
{if (x > k){memset(ss, 0, sizeof(ss));for (int i = 1; i <= k; ++i){if (!ss[s[i]]) ss[s[i]] = i;//找到相连的点中的第一个点,以这个点为父节点,ss和上面重复利用fa[i] = ss[s[i]];}fa[k + 1] = k + 1;pp(1, z);return;}for (int i = 1; i <= y; ++i)//再找一次有效状态{s[x] = i;dfs2(x + 1, y, z * 10 + i);s[x] = 0;}s[x] = y + 1;dfs2(x + 1, y + 1, z * 10 + y + 1);s[x] = 0;return;
}
void Counting(ll x)//快速幂
{while(x){if (x&1) A = A * B;B = B * B;x>>=1;}return;
}
int main()
{scanf("%lld%lld", &k, &n);dfs1(1, 0, 0);//得出编号dfs2(1, 0, 0);//连接状态A.n = 1;A.m = B.n = B.m = w;Counting(n - k);//初始状态已经是前k个printf("%lld", A.a[1][1]);return 0;
}
【矩阵乘法】生成树计数(luogu 2109/NOI 2007)相关推荐
- 疯子的算法总结(九) 图论中的矩阵应用 Part 2 矩阵树 基尔霍夫矩阵定理 生成树计数 Matrix-Tree
定理: 1.设G为无向图,设矩阵D为图G的度矩阵,设C为图G的邻接矩阵. 2.对于矩阵D,D[i][j]当 i!=j 时,是一条边,对于一条边而言无度可言为0,当i==j时表示一点,代表点i的度. 即 ...
- 【BZOJ4818】【SDOI2017】序列计数 [矩阵乘法][DP]
序列计数 Time Limit: 30 Sec Memory Limit: 128 MB [Submit][Status][Discuss] Description Alice想要得到一个长度为n的 ...
- P3702-[SDOI2017]序列计数【矩阵乘法】
正题 题目链接:https://www.luogu.com.cn/problem/P3702 题目大意 nnn个不超过mmm的正整数,要求和是ppp的倍数且至少有一个质数. 解题思路 用总方案数减去只 ...
- 信息学奥赛一本通 1125:矩阵乘法 | OpenJudge NOI 1.8 08
[题目链接] ybt 1125:矩阵乘法 OpenJudge NOI 1.8 09:矩阵乘法 [题目考点] 1. 二维数组遍历 [题解代码] 解法1: #include<bits/stdc++. ...
- Ybtoj-排列计数【矩阵乘法,分块幂】
正题 题目链接:http://noip.ybtoj.com.cn/contest/596/problem/1 题目大意 TTT组询问给出nnn求有多少个nnn的排列满足第一个是111并且相邻的差不超过 ...
- 【矩阵乘法】【倍增】美食家(luogu 6772)
美食家 题目大意 给你一个有向图,边权为经过所需时间 每个点有一个点权,有些点还有有特殊的点权 当你到达一个点后,可以获得该点的点权(重复经过可以重复获得,但不能停留),若在某个时间到某个点,则可获得 ...
- BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...
- BZOJ4180: 字符串计数 SAM+矩阵乘法
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...
- [BZOJ]4180: 字符串计数 SAM+矩阵乘法+二分
Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...
最新文章
- 入门单片机选择51还是stm32?入门单片机有哪些好的教学视频?
- pandas替换列值
- C#中的 具名参数 和 可选参数
- Hit or Miss
- Openfire及Spark配置(Mac)
- python认识if语句_python初认识、基础数据类型以及 if 流程控制
- JS 数据处理技巧及小算法汇总(转载)
- Qt 常用类——QStandardItemModel
- 二叉树的三种非递归遍历
- 软件项目管理案例教程课后答案
- windows内核基础
- 生产管理MES系统框架
- Xcode5帮助文档!
- JavaScript练习(一)——跟随鼠标移动
- github之处理“忒修斯之船”问题
- android模拟器 对比,安卓模拟器多开用哪个模拟器好?实测数据对比哪个好用
- linux服务被植入挖矿(2t3ik与ddgs)解决方式
- 2014年注电考试心得
- 雪碧的N种新潮喝法雪碧的N种新潮喝法 - 生活至上,美容至尚!
- android 通过service 执行AlarmManager 自动更换壁纸
热门文章
- 混凝土墙开洞_满城混凝土柱子切割资质齐全
- python编写程序计算1+2+3+......+100和_Python3:计算两个列表总和为100的所有排列的最有效方法是什么?...
- 计算机技术题目,计算机技术题目.doc
- 数据库年月日时分秒_数据库基本使用系列(二)
- UVA - 514 Rails-栈
- [蓝桥杯2017决赛]图书排列-next_permutation枚举
- 2018 蓝桥杯省赛 B 组模拟赛(一) 封印之门+最短路径之Floyd
- 递归算法(一)递归概念与思路
- java printf 版本_java – PrintStream类型中的printf(String,Object ...
- 2019-03-11-算法-进化(求众数)