NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)
模拟 kruscal 的建最小生成树的过程,我们应该把树边一条一条加进去;在加下一条之前先把权值在这一条到下一条的之间的那些边都连上。连的时候要保证图的连通性不变。
已经加了一些树边之后,图的连通性是怎样的呢?这可以是一个整数划分的问题。据说方案只有4万多,所以可以搜一下,搜出有 k 个连通块的方案数。
为了转移和转移时算方案数,还要记录每个方案的:各个连通块的点数,所有的空位(可放边)数。
可以用 map 来存状态。 map 的角标是一个随便哈希的值,map 的值是这个状态的编号,也是这个状态的其他信息在那些数组里的角标。这样要算下一个状态是谁的时候就可以通过记录的“各个连通块的点数”找到”下一个状态的各个连通块的点数“,再用一样的方法哈希起来,利用 map 就能找到下一个状态的编号了。
因为不太会写,所以就学习(抄)了一下别人的。
1.注意算排列时判 n<m !数组越界本地可能答案正确,但交上去就会爆。
2.不知 1e4 是怎么确定的?
3.学题解 N=41 WA了最后两个点,改成45就A了。不知为何。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ull unsigned long long
#define ll long long
using namespace std;
const int N=,M=1e4,mod=1e9+,base=M;//N=41会WA两个点?!
int n,a[N],cd[N],vec[N][M][N],edg[N][M];//N的情况里第M个的 空位/第N个连通块的点数
int dp[N][M],lm,tmp[N],id[N][N],tmpx[N],top;
int jc[N*N],jcn[N*N];
ull hsh;
map<ull,int> mp[N];//用值得到另一个角标(cd)
int rdn()
{
int ret=;bool fx=; char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=; ch=getchar();}
while(ch>=''&&ch<='') ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return fx?ret:-ret;
}
int pw(int x,int k)
{
int ret=;while(k){if(k&1ll)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1ll;}return ret;
}
void init()
{
lm=(n*(n-)>>);//not n
jc[]=;
for(int i=;i<=lm;i++) jc[i]=(ll)jc[i-]*i%mod;
jcn[lm]=pw(jc[lm],mod-);
for(int i=lm-;i>=;i--) jcn[i]=(ll)jcn[i+]*(i+)%mod;
}
void dfs(int sm,int cr,int lst)
{
if(lst*(lm-cr+)>sm) return;
if(cr>lm)
{
hsh=;
for(int i=;i<cr;i++)hsh=hsh*base+tmp[i];
mp[lm][hsh]=++cd[lm];
for(int i=;i<cr;i++)
{
vec[lm][cd[lm]][i]=tmp[i];
edg[lm][cd[lm]]+=(tmp[i]*(tmp[i]-)>>);
}
//printf("edg[%d][%d]=%d\n",lm,cd[lm],edg[lm][cd[lm]]);
return;
}
if(cr==lm)
{
tmp[cr]=sm;dfs(,cr+,);//有剪枝,所以一定不降
return;
}
for(int i=lst;i<=sm;i++)
{
tmp[cr]=i;
dfs(sm-i,cr+,i);
}
}
int P(int n,int m)
{
if(n<m) return ;//!!!!!!
//printf("jc[%d]=%d jcn[%d]=%d\n",n,jc[n],n-m,jcn[n-m]);
return (ll)jc[n]*jcn[n-m]%mod;
}
int main()
{
n=rdn();
init();
for(int i=n;i>;i--) a[i]=rdn(); a[]=(n*(n-)>>);
for(int i=;i<=n;i++) lm=i,dfs(n,,);
dp[n][]=;
for(int i=n;i>;i--)
for(int s=;s<=cd[i];s++)
{
//printf("y dp[%d][%d]=%d\n",i,s,dp[i][s]);
//printf("%d-%d=%d %d-%d-1=%d\n",edg[i][s],a[i+1],edg[i][s]-a[i+1],a[i],a[i+1],a[i]-a[i+1]-1);
dp[i][s]=(ll)dp[i][s]*P(edg[i][s]-a[i+],a[i]-a[i+]-)%mod;
//printf("now dp[%d][%d]=%d(P=%d)\n",i,s,dp[i][s],P(edg[i][s]-a[i+1],a[i]-a[i+1]-1));
memset(id,,sizeof id);
for(int j=;j<=i;j++)tmp[j]=vec[i][s][j];
for(int u=;u<=i;u++)
for(int v=u+;v<=i;v++)//哪两个集合
{
//printf("i=%d s=%d tmp[%d]=%d tmp[%d]=%d\n",i,s,u,tmp[u],v,tmp[v]);
if(!id[tmp[u]][tmp[v]])
{
top=;
for(int p=;p<=i;p++)
if(p!=u&&p!=v)tmpx[++top]=tmp[p];
tmpx[++top]=tmp[u]+tmp[v];
for(int p=top-;p;p--)//插排
if(tmpx[p]>tmpx[p+])swap(tmpx[p],tmpx[p+]);
else break;//else
hsh=;
for(int p=;p<=top;p++)
hsh=hsh*base+tmpx[p];
id[tmp[u]][tmp[v]]=mp[i-][hsh];
//printf("id[%d][%d]=%d\n",tmp[u],tmp[v],id[tmp[u]][tmp[v]]);
}
dp[i-][id[tmp[u]][tmp[v]]]=
(dp[i-][id[tmp[u]][tmp[v]]]+(ll)dp[i][s]*tmp[u]*tmp[v])%mod;
//printf("dp[%d][%d]=%d(dp=%d tmu=%d tmv=%d)\n",i-1,id[tmp[u]][tmp[v]],dp[i-1][id[tmp[u]][tmp[v]]],dp[i][s],tmp[u],tmp[v]);
}
}
//printf("%d-%d=%d %d-%d-1=%d\n",edg[1][1],a[2],edg[1][1]-a[2],a[1],a[2],a[1]-a[2]-1);
dp[][]=(ll)dp[][]*P(edg[][]-a[],a[]-a[]-)%mod;
printf("%d\n",dp[][]);
return ;
}
NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)的更多相关文章
- NOI.ac #31 MST DP、哈希
题目传送门:http://noi.ac/problem/31 一道思路好题考虑模拟$Kruskal$的加边方式,然后能够发现非最小生成树边只能在一个已经由边权更小的边连成的连通块中,而树边一定会让两个 ...
- NOI.AC #31 MST —— Kruskal+点集DP
题目:http://noi.ac/problem/31 好题啊! 题意很明白,对于有关最小生成树(MST)的题,一般是要模拟 Kruskal 过程了: 模拟 Kruskal,也就是把给出的 n-1 条 ...
- NOI.AC #31. MST
好像又是神仙dp....gan了一早上 首先这是个计数类问题,上DP, 对于一个最小生成树,按照kruskal是一个个联通块,枚举边小到大合成的 假如当前边是树边,那么转移应该还是枚举两个块然后合并 ...
- [NOI.AC#31]MST 计数类DP
链接 注意到 \(n\) 只有40,爆搜一下发现40的整数拆分(相当于把 \(n\) 分成几个联通块)很少 因此可以枚举联通块状态来转移,这个状态直接用vector存起来,再用map映射,反正40也不 ...
- noi.ac #39 MST
MST 模板题 #include <iostream> #include <cstdio> #include <algorithm> #include <cm ...
- 【noi 2.6_8787】数的划分(DP){附【转】整数划分的解题方法}
题意:问把整数N分成K份的分法数.(与"放苹果"不同,在这题不可以有一份为空,但可以类比)解法:f[i][j]表示把i分成j份的方案数.f[i][j]=f[i-1][j-1](新开 ...
- NOI.AC: NOIP2018 全国模拟赛习题练习
闲谈: 最后一个星期还是不浪了,做一下模拟赛(还是有点小虚) #30.candy 题目: 有一个人想买糖吃,有两家商店A,B,A商店中第i个糖果的愉悦度为Ai,B商店中第i个糖果的愉悦度为Bi 给出n ...
- 整数划分 Integer Partition(一)
话说今天百度面试,可能是由于我表现的不太好,面试官显得有点不耐烦,说话的语气也很具有嘲讽的意思,搞得我有点不爽.Whatever,面试中有问到整数划分问题,回答这个问题过程中被面试官搞的不胜其烦,最后 ...
- BZOJ1263: [SCOI2006]整数划分
1263: [SCOI2006]整数划分 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 677 Solved: 332[Submit][Status] ...
随机推荐
- 多通道 移位寄存器 verilog
// Quartus II Verilog Template // Basic 64-stage shift register with multiple taps module basic_shif ...
- ubuntu boost.python
安装boost(未尝试只安装 libboost-python-dev) sudo apt-get install libboost-all-dev 新建hello_ext.cpp,输入以下代码 1 c ...
- warning: mysql-community-libs-5.7.11-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5
1.错误描写叙述 [root@ mysql]# rpm -ivh mysql-community-libs-5.7.11-1.el7.x86_64.rpm warning: mysql-communi ...
- 一套ui满足ios与android界面
1.android 画布宽高720*1280的标准来切图生成xhdpi标准图,后自动生成mdpi.hdpi.xhdpi.xxhdpi四套图. 2.ios画布宽高640 x 1136的标准来切图生成xh ...
- JavaScript框架——jquery
1.jQuery编程常识 ————————如何进行jQuery插件开发 2.五星评分——jQuery Raty 一个很棒的jQuery评分插件—jQuery Raty 3.能感 ...
- Micro Python:运行在微控制器上的Python
Micro Python运行在微控制器上的Python.遵守MIT协议.由剑桥大学的理论物理学家乔治·达明设计.和Arduino类似,但Micro Python更强大. Micro Python的软件 ...
- Drcom账户管理Server端解说
https://www.github.com/xiyouMc 首先今天要讲的是针对Drcom查询账户URL的解析和抓取数据. Drcom是大学生宿舍上网普遍使用的联网client,然而对于自己账 ...
- System.TypeLoadException: Could not load type 'System.IO.Compression.CompressionLevel' from assembly 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
1.提示错误信息: zipSystem.TypeLoadException: Could not load type 'System.IO.Compression.CompressionLevel' ...
- 搭建sftp服务+nginx代理
在公司,经常会用到sftp服务,比如两个公司对接生产项目,其中一方,要在sftp上上传pdf文件,另一方公司要在sftp服务器上用nginx代理直接下载pdf文件.下面就说说我在实际中应用到的sftp ...
- 【题解】P3939数颜色
[题解]P3939 数颜色 不要数据结构和模板学傻了... 考虑到兔子们交换都是相邻的,说明任何一次交换只会引起\(O(1)\)的变化. 我们开很多\(vector\)存没种兔子的下标就好了.到时候二 ...