题目传送门:http://noi.ac/problem/31

一道思路好题
考虑模拟$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、哈希的更多相关文章

  1. NOI.AC #31 MST —— Kruskal+点集DP

    题目:http://noi.ac/problem/31 好题啊! 题意很明白,对于有关最小生成树(MST)的题,一般是要模拟 Kruskal 过程了: 模拟 Kruskal,也就是把给出的 n-1 条 ...

  2. NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)

    题目:http://noi.ac/problem/31 模拟 kruscal 的建最小生成树的过程,我们应该把树边一条一条加进去:在加下一条之前先把权值在这一条到下一条的之间的那些边都连上.连的时候要 ...

  3. [NOI.AC#31]MST 计数类DP

    链接 注意到 \(n\) 只有40,爆搜一下发现40的整数拆分(相当于把 \(n\) 分成几个联通块)很少 因此可以枚举联通块状态来转移,这个状态直接用vector存起来,再用map映射,反正40也不 ...

  4. NOI.AC #31. MST

    好像又是神仙dp....gan了一早上 首先这是个计数类问题,上DP, 对于一个最小生成树,按照kruskal是一个个联通块,枚举边小到大合成的 假如当前边是树边,那么转移应该还是枚举两个块然后合并 ...

  5. noi.ac #39 MST

    MST 模板题 #include <iostream> #include <cstdio> #include <algorithm> #include <cm ...

  6. [NOI.AC 2018NOIP模拟赛 第三场 ] 染色 解题报告 (DP)

    题目链接:http://noi.ac/contest/12/problem/37 题目: 小W收到了一张纸带,纸带上有 n个位置.现在他想把这个纸带染色,他一共有 m 种颜色,每个位置都可以染任意颜色 ...

  7. NOI.AC#2139-选择【斜率优化dp,树状数组】

    正题 题目链接:http://noi.ac/problem/2139 题目大意 给出\(n\)个数字的序列\(a_i\).然后选出一个不降子序列最大化子序列的\(a_i\)和减去没有任何一个数被选中的 ...

  8. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

  9. NOI.AC WC模拟赛

    4C(容斥) http://noi.ac/contest/56/problem/25 同时交换一行或一列对答案显然没有影响,于是将行列均从大到小排序,每次处理限制相同的一段行列(呈一个L形). 问题变 ...

随机推荐

  1. python之管道, 事件, 信号量, 进程池

    管道:双向通信 2个进程之间相互通信 from multiprocessing import Process, Pipe def f1(conn): from_zjc_msg = conn.recv( ...

  2. centos7 Linux 安装jdk1.8

    在CentOS7上安装JDK1.8 1 通过 xshell 连接到CentOS7 服务器: 2 进入到目录 /usr/local/ 中(一般装应用环境我们都会在这个目录下装,也可自行选择目录): cd ...

  3. Sqlserver精简安装选项

  4. (网页)java中Collections.sort排序详解(转)

    转自CSDN: Comparator是个接口,可重写compare()及equals()这两个方法,用于比价功能:如果是null的话,就是使用元素的默认顺序,如a,b,c,d,e,f,g,就是a,b, ...

  5. Java ——基础语法

    package myhello; // 本类所在的包的路径 import af.util.AfMath; // 导入对应的类 import java.util.Random; // 导入随机数的类 p ...

  6. CSS| 框模型-定位及相關屬性

    CSS 定位 (Positioning) 属性允许你对元素进行定位. CSS 定位和浮动 CSS 为定位和浮动提供了一些属性,利用这些属性,可以建立列式布局,将布局的一部分与另一部分重叠,还可以完成多 ...

  7. 辽宁移动宽带体验及魔百盒M101s-2刷机

    一.背景 坐标:辽宁 某城,移动宽带100M. 设备:移动赠送,华为光猫一只,魔百盒M101s-2电视盒子 一只,据安装人员说这个魔百盒是移动自己开发设计的. 二.上网体验 上网:浏览一般网站没问题. ...

  8. Python交互模式下代码自动补全

    这个功能是以lib的形式提供的,配置写到home下的.pythonrc文件中, 并设置好环境变量让python启动时执行初始化: # ~/.pythonrc # enable syntax compl ...

  9. Fragment分解使用

    Fragment碎片:作为Activity的一部分,不能单独使用: 1. Fragment特点: (1)一个Fragment可以在多个Activity中重用: (2)一个Activity内部可以嵌入多 ...

  10. 阵列卡raid H730写策略write-through和write-back配置说明

    问题描述: 最近公司新进了测试服务器,但是在做阵列的时候忘记写策略里面的配置意思了 就网上查了一下,然后顺便做个笔记记录一下 write-through 数据在写入存储的同时,要写入缓存,这种方式安全 ...