bzoj1494
这道题不仅得看俞华程的论文,还得看陈丹琦的论文,否则是不可能做出来的。因为难点在构造矩阵上。
构造矩阵困难在如何表示状态,因为树不能有环,也不能不连通,这里我们引入了最小表示法来表示连续k个点的连通性。
首先我们找出所有可能的状态,dfs一下就行了,最多只有53种。然后计算每种状态的形态,状态只是表示了连通性,但没有表示之间的形态。于是我们初始每种状态形态的数量作为列向量。然后就是构造转移矩阵。这个转移矩阵表示一个状态能够转移到另一个状态,其实是每次向前移动一位。每次向前移动一位也就是说对于一个状态我们要找出所有可以成为这个状态后移一位的合法的状态。每两个状态之间系数矩阵上的值为可能的形态数,这里的形态数和刚才不太一样,向后移一位说明把当前k个点去掉了第一个点,然后又添加了一个点。这里我们用二进制枚举连通性,也就是说新加入的点和之前k个点中哪些点是联通的。那么这样的连通性会有很多情况,比如说原来的最小表示是001,二进制枚举出来的是11,那么新的点既要和第一个联通块联通,也要和第二个联通块联通,也就是有两种情况,即是(设这个点为4,之前为123)(4->1, 4->3) (4->2,4->3)两种联通情况。
最后统计答案是这样做的,因为最后只有一种合法状态,即0....0,必须所有都联通,所以sigma(f[i][1]*ret[i][1]),i->1表示所有能转移到1状态的情况。
然后就可以矩阵快速幂了。。。
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long ll;
- const int N = , M = , mod = ;
- struct mat {
- ll a[N][N];
- } A, f;
- ll k, n;
- int mir[N], cnt[N], p[N], bit[], vis[N];
- ll power(ll x, ll t)
- {
- ll ret = ;
- for(; t; t >>= , x = x * x % mod) if(t & ) ret = ret * x % mod;
- return ret;
- }
- void collect(int x)
- {
- int cnt[]; memset(cnt, , sizeof(cnt)); f.a[p[]][] = ; mir[x] = p[];
- for(int i = ; i <= k; ++i) ++cnt[x % ], x /= ;
- for(int i = ; i < k; ++i) if(cnt[i] > ) f.a[p[]][] = f.a[p[]][] * power(cnt[i], cnt[i] - ) % mod;
- }
- void dfs(int num, int d, int bound, int x)
- {
- if(d == k) { p[++p[]] = num; collect(p[p[]]); return; }
- for(int i = ; i <= bound; ++i) dfs(num + i * x, d + , max(i + , bound), x / );
- }
- void Init(int pos)
- {
- memset(bit, , sizeof(bit));
- int x = p[pos], maxn = -; bool flag = true;
- for(int j = , l = x; j < k; ++j) bit[k - j - ] = l % , l /= ;
- for(int i = ; i < k; ++i)
- {
- if(bit[i] == bit[]) flag = false;
- maxn = max(maxn, bit[i]);
- }
- int lim = << (maxn + );
- for(int i = ; i < lim; ++i)
- { //枚举连通性, 枚举和原来的每位是否联通
- if(flag && !(i & )) continue; //不成立的情况
- for(int j = , l = x; j < k; ++j) bit[k - j - ] = l % , l /= ;
- bit[k] = -;
- int ans = , l = -, tot = ; ;
- for(int j = ; j <= maxn; ++j) if(i & ( << j))
- {
- int t = ;
- for(int x = ; x < k; ++x) if(bit[x] == j) bit[x] = -, ++t;
- ans = ans * t;
- }
- memset(vis, , sizeof(vis));
- for(int j = ; j <= k; ++j) if(!vis[j])
- {
- int color = bit[j]; bit[j] = ++l; vis[j] = ;
- for(int x = ; x <= k; ++x) if(bit[x] == color && !vis[x])
- bit[x] = l, vis[x] = ;
- }
- for(int j = ; j <= k; ++j) tot = tot * + bit[j];
- A.a[pos][mir[tot]] = ans % mod;
- }
- }
- mat operator * (mat A, mat B)
- {
- mat ret; memset(ret.a, , sizeof(ret.a));
- for(int i = ; i <= p[]; ++i)
- for(int j = ; j <= p[]; ++j)
- for(int k = ; k <= p[]; ++k) ret.a[i][j] = (ret.a[i][j] + A.a[i][k] % mod * B.a[k][j] % mod) % mod;
- return ret;
- }
- int main()
- {
- scanf("%d%lld", &k, &n);
- if(k >= n) { printf("%lld\n", power(n, n - )); return ; }
- int base = ; for(int i = ; i < k; ++i) base = base * ;
- dfs(, , , base);
- for(int i = ; i <= p[]; ++i) Init(i);
- mat ret; memset(ret.a, , sizeof(ret.a)); for(int i = ; i <= p[]; ++i) ret.a[i][i] = ;
- for(ll t = n - k; t; t >>= , A = A * A) if(t & ) ret = ret * A;
- ll ans = ;
- for(int i = ; i <= p[]; ++i) ans = (ans + f.a[i][] * ret.a[i][]) % mod;
- printf("%lld\n", ans);
- return ;
- }
bzoj1494的更多相关文章
- 【BZOJ1494】【NOI2007】生成树计数(动态规划,矩阵快速幂)
[BZOJ1494][NOI2007]生成树计数(动态规划,矩阵快速幂) 题面 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现: ·n个结点的环的生成树个数为 ...
- [BZOJ1494]生成树计数
[BZOJ1494] [NOI2007]生成树计数 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现:·n个结点的环的生成树个数为n.·n个结点的完全图的生成树 ...
- bzoj1494 生成树计数 (dp+矩阵快速幂)
题面欺诈系列... 因为一个点最多只能连到前k个点,所以只有当前的连续k个点的连通情况是对接下来的求解有用的 那么就可以计算k个点的所有连通情况,dfs以下发现k=5的时候有52种. 我们把它们用类似 ...
- BZOJ1494 [NOI2007]生成树计数
题意 F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser autoint Logout 捐赠本站 Probl ...
- [BZOJ1494][NOI2007]生成树计数 状压dp 并查集
1494: [NOI2007]生成树计数 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 793 Solved: 451[Submit][Status][ ...
- bzoj1494【Noi2007】生成树计数
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1494 sol :前排膜拜http://blog.csdn.net/qpswwww/artic ...
- 插头dp初探
问题描述 插头dp用于解决一类可基于图连通性递推的问题.用插头来表示轮廓线上的连通性,然后根据连通性与下一位结合讨论进行转移. 表示连通性的方法 与字符串循环最小表示不同,这种方法用于给轮廓线上的联通 ...
- Noip前的大抱佛脚----赛前任务
赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...
随机推荐
- Leetcode加一 (java、python3)
加一 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. Given ...
- java mysql prepareStatement模糊查询like使用注意
今天在使用mysql 的like语句是,发现prepareStatement的like语句和一般的=写法有一样. 当要使用prepareStatement的like查询时,按照一般写法,都会写成: S ...
- pandas 处理 excel
先写下来,以免后续忘记,有很多都是之前用过的, 依旧忘!!! 嘤嘤嘤 data_file = pandas.read_excel('/imporExcel/2017_7_7.xlsx',sep = ' ...
- ssh中将常用的命令做别名
1.vim ~/.bashrc 将光标落到user下面 2. 输入 alias x=‘ssh的命令’ 3.按ESC键,退出输入状态: 4.按:,然后输入wq,保存退出: 5. source ~/.ba ...
- LINUX-APT 软件工具 (Debian, Ubuntu 以及类似系统)
apt-get install package_name 安装/更新一个 deb 包 apt-cdrom install package_name 从光盘安装/更新一个 deb 包 apt-get u ...
- Python学习之前
编程语言的分类: 1.机器语言:直接以0和1编写指令代码,计算机能直接识别处理: 特点:运行速度最快,太复杂,开发效率低,可执行操作最多. 2.汇编语言:本质上依然是机器语言,用英文代替0和1,更容易 ...
- saltstack(四) saltstack的targeting、分组
targeting支持如下matcher: Globing : '*', 正则: 指定-E参数,正则表达式匹配多个 List: 指定-L参数,salt -E 'web1-(prod|devel)' t ...
- nyoj 911 Registration system(map)
Registration system 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 A new e-mail service "Berlandesk&q ...
- noip模拟赛 捡金币
问题描小空正在玩一个叫做捡金币的游戏.游戏在一个被划分成 n行 n列的网格状场地中进行.每一个格子中都放着若干金币,并且金币的数量会随着时间而不断变化. 小空的任务就是在网格中移动,拾取尽量多的金币. ...
- 常州模拟赛d7t1 亲戚
分析:把题目换个方式理解,就是把各个点排成一列,并且指定了若干对的先后次序,问你有多少种序列满足要求. 显然是一道dp题,直接推出方程似乎有点点困难,那么先看看数据特点. 1.有一些点满足fi=0,那 ...