【Luogu】P4208最小生成树计数(状压乱搞)
最小生成树有两个性质,两个性质都知道的话这题就变成码农题了。
1、无论最小生成树长什么样,所有权值的边的数量是不变的。比如我有棵最小生成树有两条权值为2的边四条权值为1的边,那这个图的所有最小生成树都是两条权值为2的边四条权值为1的边。
2、无论最小生成树长什么样,把边从小到大排序,某一权值的边连完后,联通块一定是固定的。
这就提示了我们先求一遍最小生成树,得到生成树里每个权值的边都有几条,然后枚举权值,状压当前权值选的边集,看能不能把选出来的这些边都摁进森林里去。如果能的话该权值的连接方案数就+1.
枚举完之后,因为第二条所以我们直接把所有该权值的边的两个端点合到一个并查集里就好了。
最后乘法原理得到答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#define maxn 10000
#define mod 31011
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} struct Edge{
int from,to,val;
}edge[maxn],q[maxn],d[maxn];
bool cmp(Edge a,Edge b){ return a.val<b.val; }
int head[maxn],num;
inline void add(int from,int to,int val){
edge[++num]=(Edge){head[from],to,val};
head[from]=num;
} bool vis[maxn];
int sum[maxn];
int w[maxn];
int size;
struct fus{
int father[maxn];
inline void clear(int n){ for(int i=;i<=n;++i) father[i]=i; }
int find(int x){
if(father[x]!=x) father[x]=find(father[x]);
return father[x];
}
inline void unionn(int x,int y){
x=find(x); y=find(y);
father[y]=x;
}
}c,r,right; inline int getlen(int x){
int ans=;
while(x){
if(x&) ans++;
x>>=;
}
return ans;
} int ans[maxn];
int pre[maxn]; void copy(int x,int *a,int *b){ for(int i=;i<=x;++i) a[i]=b[i];} int main(){
int n=read(),m=read();
for(int i=;i<=m;++i) q[i]=(Edge){read(),read(),read()};
c.clear(n);
sort(q+,q+m+,cmp);
int cnt=,last=,now=;
for(int i=;i<=m;++i){
//离散化
now=q[i].val;
if(q[i].val==last) q[i].val=size;
else q[i].val=++size;
last=now; int from=q[i].from,to=q[i].to;
if(c.find(from)==c.find(to)) continue;
c.unionn(from,to);
vis[q[i].val]=;
sum[q[i].val]++;
cnt++;
if(cnt==n-) break;
}
if(cnt<n-){
printf("");
return ;
}
c.clear(n);
cnt=;
int maxval=;
for(int i=;i<=m;++i)
if(vis[q[i].val]){
d[++cnt]=q[i];
w[q[i].val]++;
maxval=max(maxval,q[i].val);
}
last=;
for(int i=;i<=maxval;++i){
int Max=<<w[d[last+].val];
copy(n,right.father,c.father);
for(int j=;j<Max;++j){
if(getlen(j)!=sum[d[last+].val]) continue;
bool flag=;
copy(n,r.father,c.father);
for(int k=;(<<k)<=j;++k)
if(j&(<<k)){
int ret=(k+)+last;
if(r.find(d[ret].from)==r.find(d[ret].to)){
flag=;
break;
}
r.unionn(d[ret].from,d[ret].to);
}
if(flag==){
ans[d[last+].val]++;
copy(n,right.father,r.father);
}
}
copy(n,c.father,right.father);
last+=w[d[last+].val];
}
for(int i=;i<=maxval;++i)
if(w[i]){
last=i;
break;
}
for(int i=last;i<=maxval;++i){
if(ans[i]&&i!=last){
ans[i]=(ans[i]*ans[last])%mod;
last=i;
}
}
printf("%d\n",ans[last]);
return ;
}
【Luogu】P4208最小生成树计数(状压乱搞)的更多相关文章
- [BZOJ1494][NOI2007]生成树计数 状压dp 并查集
1494: [NOI2007]生成树计数 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 793 Solved: 451[Submit][Status][ ...
- luogu 2704 炮兵阵地 状压dp
状压的基础题吧 第一次看感觉难上天,后来嘛就.. 套路:先根据自身状态筛出可行状态,再根据地图等其他限制条件筛选适合的状态加入答案 f i,j,k 分别代表 行数,本行状态,上行状态,再累加答案即可 ...
- HDU5117 Fluorescent 期望 计数 状压dp 动态规划
原文链接https://www.cnblogs.com/zhouzhendong/p/HDU5117.html 题目传送门 - HDU5117 题意 $T$ 组数据. 给你 $n$ 盏灯 ,$m$ 个 ...
- Luogu 3959 [NOIP2017] 宝藏- 状压dp
题解 真的想不到这题状压的做法...听说还有跑的飞快的模拟退火,要是现场做绝对滚粗QAQ. 不考虑深度,先预处理出 $pt_{i, S}$ 表示让一个不属于 集合 $S$ 的 点$i$ 与点集 $S$ ...
- Luogu P1134 阶乘问题 【数学/乱搞】 By cellur925
输入输出格式 输入格式: 仅一行包含一个正整数 NN . 输出格式: 一个整数,表示最右边的非零位的值. 输入输出样例 输入样例#1: 12 输出样例#1: 6 说明 USACO Training S ...
- [CSP-S模拟测试]:统计(树状数组+乱搞)
题目传送门(内部题120) 输入格式 第一行,两个正整数$n,m$. 第二行,$n$个正整数$a_1,a_2,...,a_n$,保证$1\leqslant a_i\leqslant n$,可能存在相同 ...
- BZOJ 1012: [JSOI2008]最大数maxnumber 单调队列/线段树/树状数组/乱搞
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 4750 Solved: 2145[Submi ...
- hdu 5094 状压bfs+深坑
http://acm.hdu.edu.cn/showproblem.php?pid=5094 给出n*m矩阵 给出k个障碍,两坐标之间存在墙或门,门最多10种,状压可搞 给出s个钥匙位置及编号,相应的 ...
- hdu 1429 bfs+状压
题意:这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方.刚开始 Ignatius被关在(sx,sy)的位置,离开地牢的门 ...
随机推荐
- CPP-基础:new int[]跟int()的区别
1. new int[] 是创建一个int型数组,数组大小是在[]中指定,例如: int * p = new int[10]; //p执行一个长度为10的int数组.2. new int()是创建一个 ...
- Ubuntu编译Android源码过程中的空间不足解决方法
Android源码一般几十G,就拿Android5.0来说,下载下来大概也有44G左右,和编译产生的文件以及Ubuntu系统占用的空间加起来,源码双倍的空间都不够有.编译源码前能分配足够的空间再好不过 ...
- java基础—static关键字
一.static关键字
- js完成打印功能
最近在做项目要求实现打印功能,我采用js方式来实现 window.print();会弹出打印对话框,打印的是window.docunemt.body.innerHTML中的内容,可以局部打印,也可以全 ...
- Nginx: ubuntu系统上查找nginx.conf配置文件的路径
问题描述:在ubuntu系统上,找到nginx.conf文件的位置. 解决方法:在终端窗口中,输入命令:nginx -t 回显中就可以看到nginx.conf文件的路径了. 参考:https://bl ...
- Mysql常用运算符与函数汇总
Mysql常用运算符与函数汇总 本文给大家汇总介绍了mysql中的常用的运算符以及常用函数的用法及示例,非常的全面,有需要的小伙伴可以参考下 我们先把数据表建好 use test;create tab ...
- C#基础-数组-冒泡排序
冒泡排序基础 冒泡排序原理图分析 tmp在算法中起到数据交换的作用 int[] intNums = { 12,6,9,3,8,7 }; int tmp = intNums[0]; // 一共5次冒泡, ...
- 01Qt中的隐式共享
隐式共享 隐式共享又称为回写复制(copy on write).当两个对象共享同一分数据时(通过浅拷贝实现数据共享),如果数据不改变,则不进行数据的复制.而当某个对象需要需要改变数据时,则进行深拷 ...
- 如何用纯 CSS 创作一台拍立得照相机
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/YjYgey 可交互视频 此视频是可 ...
- 命令行下创建MySQL数据库与创建用户以及授权
先以root用户登录mysql: C:\Users\XXX>mysql -u root -p 输入密码后登录,接下来操作如下: 1.创建数据库 语法:create schema [数据库名称] ...