生成树计数

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)相关推荐

  1. 疯子的算法总结(九) 图论中的矩阵应用 Part 2 矩阵树 基尔霍夫矩阵定理 生成树计数 Matrix-Tree

    定理: 1.设G为无向图,设矩阵D为图G的度矩阵,设C为图G的邻接矩阵. 2.对于矩阵D,D[i][j]当 i!=j 时,是一条边,对于一条边而言无度可言为0,当i==j时表示一点,代表点i的度. 即 ...

  2. 【BZOJ4818】【SDOI2017】序列计数 [矩阵乘法][DP]

    序列计数 Time Limit: 30 Sec  Memory Limit: 128 MB [Submit][Status][Discuss] Description Alice想要得到一个长度为n的 ...

  3. P3702-[SDOI2017]序列计数【矩阵乘法】

    正题 题目链接:https://www.luogu.com.cn/problem/P3702 题目大意 nnn个不超过mmm的正整数,要求和是ppp的倍数且至少有一个质数. 解题思路 用总方案数减去只 ...

  4. 信息学奥赛一本通 1125:矩阵乘法 | OpenJudge NOI 1.8 08

    [题目链接] ybt 1125:矩阵乘法 OpenJudge NOI 1.8 09:矩阵乘法 [题目考点] 1. 二维数组遍历 [题解代码] 解法1: #include<bits/stdc++. ...

  5. Ybtoj-排列计数【矩阵乘法,分块幂】

    正题 题目链接:http://noip.ybtoj.com.cn/contest/596/problem/1 题目大意 TTT组询问给出nnn求有多少个nnn的排列满足第一个是111并且相邻的差不超过 ...

  6. 【矩阵乘法】【倍增】美食家(luogu 6772)

    美食家 题目大意 给你一个有向图,边权为经过所需时间 每个点有一个点权,有些点还有有特殊的点权 当你到达一个点后,可以获得该点的点权(重复经过可以重复获得,但不能停留),若在某个时间到某个点,则可获得 ...

  7. BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  8. BZOJ4180: 字符串计数 SAM+矩阵乘法

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  9. [BZOJ]4180: 字符串计数 SAM+矩阵乘法+二分

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

最新文章

  1. 入门单片机选择51还是stm32?入门单片机有哪些好的教学视频?
  2. pandas替换列值
  3. C#中的 具名参数 和 可选参数
  4. Hit or Miss
  5. Openfire及Spark配置(Mac)
  6. python认识if语句_python初认识、基础数据类型以及 if 流程控制
  7. JS 数据处理技巧及小算法汇总(转载)
  8. Qt 常用类——QStandardItemModel
  9. 二叉树的三种非递归遍历
  10. 软件项目管理案例教程课后答案
  11. windows内核基础
  12. 生产管理MES系统框架
  13. Xcode5帮助文档!
  14. JavaScript练习(一)——跟随鼠标移动
  15. github之处理“忒修斯之船”问题
  16. android模拟器 对比,安卓模拟器多开用哪个模拟器好?实测数据对比哪个好用
  17. linux服务被植入挖矿(2t3ik与ddgs)解决方式
  18. 2014年注电考试心得
  19. 雪碧的N种新潮喝法雪碧的N种新潮喝法 - 生活至上,美容至尚!
  20. android 通过service 执行AlarmManager 自动更换壁纸

热门文章

  1. 混凝土墙开洞_满城混凝土柱子切割资质齐全
  2. python编写程序计算1+2+3+......+100和_Python3:计算两个列表总和为100的所有排列的最有效方法是什么?...
  3. 计算机技术题目,计算机技术题目.doc
  4. 数据库年月日时分秒_数据库基本使用系列(二)
  5. UVA - 514 Rails-栈
  6. [蓝桥杯2017决赛]图书排列-next_permutation枚举
  7. 2018 蓝桥杯省赛 B 组模拟赛(一) 封印之门+最短路径之Floyd
  8. 递归算法(一)递归概念与思路
  9. java printf 版本_java – PrintStream类型中的printf(String,Object ...
  10. 2019-03-11-算法-进化(求众数)