NOI.ac #31 MST DP、哈希
考虑模拟$Kruskal$的加边方式,然后能够发现非最小生成树边只能在一个已经由边权更小的边连成的连通块中,而树边一定会让两个连通块合为一个,故考虑以连通块为切入点设计$DP$
设字符串$s_1s_2s_3...s_i,s_1 \geq s_2 \geq s_3 \geq ... \geq s_i$表示某一个图中各个连通块的大小(可以发现我们只关心连通块有多大,但不关心连通块内具体有哪些点,因为当所有连通块大小一一对应的时候,方案也是一一对应的),$f_{s_1s_2s_3...s_i}$为通过连边达到这个图的方案数,然后考虑状态的转移
考虑已经加入了边权从$1$至$a_{n-i}$的边,现在即将加入$a_{n-i}$至$a_{n-i+1}-1$的非树边与$a_{n-i+1}$的树边
考虑非树边的加入方案,对于一个图$s_1s_2s_3...s_i$,它的总边数为$\sum\limits_{x=1}^i\frac{s_i \times (s_i-1)}2$,已经加入了$a_{n-i}$条边,所以剩余$\sum\limits_{x=1}^i\frac{s_i \times (s_i-1)}2 - a_{n-i}$可以加入非树边,所以总共的非树边加入方案是$$P_{\sum\limits_{x=1}^i\frac{s_i \times (s_i-1)}2 - a_{n-i}}^{a_{n-i+1}-a_{n-i}-1}$$当然,如果图中非树边数量小于需要加入的非树边,方案就是0,无需转移
接下来考虑树边的加入方案,我们可以在任意两个连通块之中加入边$a_{n-i+1}$,于是枚举这两个连通块$s_x,s_y$,删除$s_x,s_y$、加入$s_x+s_y$并排序得到新的图$s_1's_2'...s_{i-1}'$,那么从$s_1s_2s_3...s_i$到$s_1's_2',...,s_{i-1}'$就有$$P_{\sum\limits_{x=1}^i\frac{s_i \times (s_i-1)}2 - a_{n-i}}^{a_{n-i+1}-a_{n-i}-1}$$种非树边加入方式与$$s_x \times s_y$$种树边加入方式,就有$$f_{s_1's_2'...s_{i-1}'} += f_{s_1s_2s_3...s_i} \times P_{\sum\limits_{x=1}^i\frac{s_i \times (s_i-1)}2 - a_{n-i}}^{a_{n-i+1}-a_{n-i}-1} \times s_x \times s_y$$的答案贡献
最后考虑$f_{s_1s_2s_3...s_i}$的存储方式,显然用$dfs$枚举可行字符串加上$Hash$是很不错的选择。还有一个问题:形如$s_1s_2s_3...s_i$的序列有多少个?可知有$N$个点时序列个数就是$N$的无序整数划分个数,$N=40$时的无序整数划分个数不超过$40000$,然后这道题就解决了
#include<bits/stdc++.h> #define MOD 1000000007 #define int long long using namespace std; map < string , int > m; ] = { , } , a[] , N; void forLSH(int num , int upNum , string s){ //枚举方案用于Hash m.insert(make_pair(s + ) , ++cntLSH)); ; i < upNum && i <= num ; i++) ; j * i <= num ; j++) forLSH(num - j * i , i , s + string(j , i)); } inline int P(int a , int b){ //计算排列 if(b > a) ; ; ; i <= a ; i++) times = times * i % MOD; return times; } inline void calc(string s){ //DP ; ){ cout << ans[t] * P((N * (N - ) >> ) - a[N - ] , (N * (N - ) >> ) - a[N - ]) % MOD; //不要忽视了最后几条边! exit(); } ; i < num ; i++) cnt += s[i] * (s[i] - ) >> ; ] - a[N - num] - ); //非树边方案总数 ; i < num ; i++) ; j < num ; j++){ //枚举连接的两个连通块 string s1 = s; s1.erase(j , ); s1.erase(i , ); int q = lower_bound(s1.begin() , s1.end() , s[j] + s[i] , greater<char>()) - s1.begin(); s1.insert(q , , s[j] + s[i]); ans[m.find(s1)->second] = (ans[m.find(s1)->second] + ans[t] * r % MOD * s[j] * s[i]) % MOD; } } void dfs(int num , int upNum , string s){ //继续枚举可行方案进行DP calc(s + )); ; i < upNum && i <= num ; i++) ; j * i <= num ; j++) dfs(num - j * i , i , s + string(j , i)); } main(){ cin >> N; ; i < N ; i++) cin >> a[i]; forLSH(N , N + , ""); dfs(N , N + , ""); ; }
NOI.ac #31 MST DP、哈希的更多相关文章
- NOI.AC #31 MST —— Kruskal+点集DP
题目:http://noi.ac/problem/31 好题啊! 题意很明白,对于有关最小生成树(MST)的题,一般是要模拟 Kruskal 过程了: 模拟 Kruskal,也就是把给出的 n-1 条 ...
- NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)
题目:http://noi.ac/problem/31 模拟 kruscal 的建最小生成树的过程,我们应该把树边一条一条加进去:在加下一条之前先把权值在这一条到下一条的之间的那些边都连上.连的时候要 ...
- [NOI.AC#31]MST 计数类DP
链接 注意到 \(n\) 只有40,爆搜一下发现40的整数拆分(相当于把 \(n\) 分成几个联通块)很少 因此可以枚举联通块状态来转移,这个状态直接用vector存起来,再用map映射,反正40也不 ...
- NOI.AC #31. MST
好像又是神仙dp....gan了一早上 首先这是个计数类问题,上DP, 对于一个最小生成树,按照kruskal是一个个联通块,枚举边小到大合成的 假如当前边是树边,那么转移应该还是枚举两个块然后合并 ...
- noi.ac #39 MST
MST 模板题 #include <iostream> #include <cstdio> #include <algorithm> #include <cm ...
- [NOI.AC 2018NOIP模拟赛 第三场 ] 染色 解题报告 (DP)
题目链接:http://noi.ac/contest/12/problem/37 题目: 小W收到了一张纸带,纸带上有 n个位置.现在他想把这个纸带染色,他一共有 m 种颜色,每个位置都可以染任意颜色 ...
- NOI.AC#2139-选择【斜率优化dp,树状数组】
正题 题目链接:http://noi.ac/problem/2139 题目大意 给出\(n\)个数字的序列\(a_i\).然后选出一个不降子序列最大化子序列的\(a_i\)和减去没有任何一个数被选中的 ...
- NOI.AC NOIP模拟赛 第六场 游记
NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...
- NOI.AC WC模拟赛
4C(容斥) http://noi.ac/contest/56/problem/25 同时交换一行或一列对答案显然没有影响,于是将行列均从大到小排序,每次处理限制相同的一段行列(呈一个L形). 问题变 ...
随机推荐
- 谷歌迂回入华:Waymo无人车抢先进驻上海!
谷歌迂回入华:Waymo无人车抢先进驻上海! https://mp.weixin.qq.com/s/d5Cw2uhykMJ9urb6Cs8aNw 谷歌又双叒叕要回归中国了?这已经是第不知道多少次的传言 ...
- Docker第二章:docker基础1--镜像,容器&仓库
镜像介绍及操作:http://www.haveneed.cn/article-detials/115 容器介绍及操作:http://www.haveneed.cn/article-detials/11 ...
- Oracle 11gR2_database在Linux下的安装
Oracle 11gR2_database在Linux下的安装 by:授客 QQ:1033553122 由于篇幅问题,采用链接分享的形式,烦请复制以下网址,黏贴到浏览器中打开,下载 http://pa ...
- Linux 学习笔记之超详细基础linux命令 Part 2
Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 1----------------- ...
- JavaScript大杂烩16 - 推荐实践
JavaScript部分 1. 总是使用===来进行相等判断 原因:由于 == 和 != 操作符存在类型转换问题,而为了保持代码中数据类型的完整性,推荐使用全等 === 和不全等 !=== 操作符. ...
- Spark编译
Spark的运行版本使用mvn编译,已经集成在源码中.如果机器有外网或者配置了http代理,可以直接调用编译命令来进行编译. windows&Linux命令如下: ./build/mvn \ ...
- 基于VMware Workstation在Windows Server 2008 R2上搭建SQL Server 2012高可用性组(AlwaysOn Group)测试环境(二)
接上篇: 以SERVER02为例,将服务器加入域,并安装故障转移群集:(SERVER02-SERVER-04操作相同)
- SQL SERVER孤立帐号的处理
Step1:查询 Use KSHR_F23 Go exec sp_change_users_login @Action='Report' Go Step2:处理 Use KSHR_F23 Go exe ...
- Debian-Linux配置网卡网络方法
Debian不同于centos系统,网卡配置不是在/etc/sysconfig/network-scrip里面,而是在/etc/network/interfaces里面 1.Debian网络配置 配置 ...
- 自定义mysql类用于快速执行数据库查询以及将查询结果转为json文件
由于每次连接数据库进行查询比较麻烦,偶尔还需要将查询结果转为json格式的文件, 因此暂时定义一个mysql的类,将这些常用的方法进行封装,便于直接调用(代码如下,个人用,没写什么注释). 注:导入了 ...