题目传送门: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之 协程

    协程: 协程是一种用户态的轻量级线程, 即协程是由用户程序自己控制调度的 1.Greenlet import time # import greenlet from greenlet import g ...

  2. vue-cli脚手架之webpack.base.conf.js

    webpack相关的重要配置文件将在这一节给出.webpack水很深啊^o^,在此先弄清楚原配文件内容的含义,后续可以自己根据实际情况配置. webpack.base.conf.js:配置vue开发环 ...

  3. 在vue配置sass

    先npm两个插件 npm install sass-loader --save-dev npm install node-sass --save-dev 然后在webpack当中配置 { test: ...

  4. OSGI企业应用开发(十四)整合Spring、Mybatis、Spring MVC

    作为一个企业级的Web应用,MVC框架是必不可少的.Spring MVC目前使用也比较广泛,本文就来介绍一下如何在OSGI应用中实现Spring.Mybatis.Spring MVC框架的整合,其中S ...

  5. SuperMap空间数据处理与制图操作短视频汇总

    转自:http://blog.csdn.net/supermapsupport/article/details/70227669 空间数据处理与制图是GIS系统建设最基础的部分,这里利用超图桌面软件- ...

  6. go 排序sort的使用

    已知一个的struct组成的数组,现在要按照数组中的一个字段排序.python有sort方法,那golang要怎么实现呢?其实golang也有sort方法,并且使用简单,功能强大. 我们先看一下sor ...

  7. git命令行clone指定分支、更新、冲突解决、提交代码步骤

    clone指定分支 : git init 初始化仓库 git clone -b 分支名  git@192.168.3.166:xxxx/xxxx.git   克隆指定分支 更新 :git status ...

  8. PyQt5--QSplitter

    # -*- coding:utf-8 -*- ''' Created on Sep 20, 2018 @author: SaShuangYiBing Comment: ''' import sys f ...

  9. MySQL InnoDB Update和Crash Recovery流程

    MySQL InnoDB Update和Crash Recovery流程 概要信息 首先介绍了Redo,Undo,Log Sequence Number (LSN),Checkpoint,Rollba ...

  10. java中的深复制和浅复制

    Java 语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文会试图澄清这一概念.并且由于Java不能通过简单 的赋值来解决对象复制的问题,在开发过程中,也 ...