容斥原理+补集转化+MinMax容斥
容斥原理的思想大家都应该挺熟悉的,然后补集转化其实就是容斥原理的一种应用。
一篇讲容斥的博文https://www.cnblogs.com/gzy-cjoier/p/9686787.html
当我们遇到正面解决很困难的问题,我们可以考虑从它的反面去思考,如果反面容易计算的话那么我们就可以用补集转化的思想先计算反面再计算正面(尤其是计数类问题)。
Min-Max容斥是一个十分有用的定理,尤其是在计算概率期望上有
一般来说:这里的Emax(S)是代表出现S所有元素的期望,Emin(T)是出现T任何一个元素的期望。
这里直接总结几道题目:
洛谷P3349 小星星
题意:给出n个点m条边的图,再给n个点的树。问有多少种方案把树映射到图上,且树上对应边图上也有。
解法:这道题解法十分巧妙地运用了容斥原理。
一个比较容易[想到的暴力解法是设计dp[i][j][S]代表把树上i点映射到图上j点后的图上点使用情况是S。那么转移也比较简单dp[x][i][S]+=dp[y][j][S'] (y是x树上的儿子,ij两点在图上有边,S-S’=i)。但是此题的n达到17,这个解法严重超时。
我们想办法在上一个办法优化,思考这个暴力办法超时的主要原因是加入了S这个状态,假如我们去掉S这个纬度,那么点的使用情况就无法得到掌握就会出现图上某个点被重复映射的不合法情况,同时去掉的好处是dp方程时间很好写且时间复杂度大大降低:dp[x][i]+=dp[y][j] (y是x树儿子,ij两点在图上有边)。于是我们想办法去掉重复映射这种情况,怎么做呢?洛谷题解上大佬提供方法十分巧妙:既然出现重复映射就是图上有某些点没用到,那么我们运用容斥原理,恰好用了n个点方案=不加限制的全集-不加限制的用n-1点方案+不加限制用n-2个点方案........这样一直下去。
- #include<bits/stdc++.h>
- using namespace std;
- const int N=;
- typedef long long LL;
- int n,m,mp[N][N];
- vector<int> G[N];
- LL dp[N][N]; //dp[i][j]表示点i映射到j的方案数(可重复映射)
- bool vis[N],ban[N]; //是否已经映射/点是否是禁止映射的
- void dfs(int x) {
- vis[x]=;
- for (int i=;i<=n;i++) dp[x][i]=;
- for (int i=;i<G[x].size();i++) {
- int y=G[x][i];
- if (vis[y]) continue;
- dfs(y);
- for (int j=;j<=n;j++) {
- LL tmp=;
- for (int k=;k<=n;k++) tmp+=dp[y][k]*(!ban[j] && !ban[k] &&mp[j][k]);
- dp[x][j]*=tmp;
- }
- }
- }
- int main()
- {
- cin>>n>>m;
- for (int i=;i<=m;i++) {
- int x,y; scanf("%d%d",&x,&y);
- mp[x][y]=mp[y][x]=; //原图
- }
- for (int i=;i<n;i++) {
- int x,y; scanf("%d%d",&x,&y);
- G[x].push_back(y); //树
- G[y].push_back(x);
- }
- int ALL=(<<n)-;
- long long ans=;
- for (int i=;i<=ALL;i++) {
- int cnt=;
- for (int j=;j<=n;j++) vis[j]=ban[j]=;
- for (int j=;j<=n;j++)
- if ((<<j-)&i) cnt++,ban[j]=;
- dfs();
- long long tmp=;
- for (int j=;j<=n;j++) tmp+=dp[][j];
- ans+=(cnt% ? - : )*tmp;
- }
- cout<<ans<<endl;
- return ;
- }
洛谷P3175 按位或
题意:刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字与之做或操作。选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1问期望多少秒后,你手上的数字变成2^n-1。
解法:这道题学了Min-Max容斥和FWT之后会变得一些简单。解法是参考https://blog.csdn.net/qq_30974369/article/details/81911124 yyb巨佬的。
这题看到比较容易想到Min-Max容斥,是计算Emax(2^n-1)这个东西并不好算,我们考虑用Min-Max容斥转化为计算Emin(T€2^n-1)。
怎么计算Emin呢?然后根据离散随机变量的期望公式 E(x)=1/p 得到
那么问题变成怎么计算sigma(p[G]) (GΛT≠ø),即所有和T有交集的几个G的概率和,其实这个东西也很难算,我们只好再次利用补集转化思想:所有有交集的G=1-所有没有交集的L(且没有交集的L=T的补集的所有子集)。
于是我们就想办法预处理出元素数据所有的子集的概率和,这个可以用FWT计算得到。
- #include<bits/stdc++.h>
- using namespace std;
- const int M=<<;
- const double eps=1e-;
- int n,cnt[M],N;
- double P[M],ans;
- void prework() {
- for(int i=;i<N;i<<=)
- for(int p=i<<,j=;j<N;j+=p)
- for(int k=;k<i;++k)
- P[i+j+k]+=P[j+k];
- }
- int main()
- {
- scanf("%d",&n);N=<<n;
- for(int i=;i<N;++i)scanf("%lf",&P[i]),cnt[i]=cnt[i>>]+(i&);
- prework();
- for(int i=;i<N;++i)
- if(-P[(N-)^i]>1e-)
- ans+=((cnt[i]&)?:-)/(-P[(N-)^i]);
- if(ans<eps)puts("INF");else printf("%.10lf\n",ans);
- return ;
- }
BZOJ 2169 连边
题意:有N个点(编号1到N)组成的无向图,已经为你连了M条边。请你再连K条边,使得所有的点的度数都是偶数。求有多少种连的方法。要求你连的K条边中不能有重边,但和已经连好的边可以重。
解法:日常不会做,解法参考https://www.cnblogs.com/NaVi-Awson/p/7581516.html这位大佬的,写得非常好。
dp[i][j]代表添加i条边之后剩下j奇点的方案数。那么写状态转移方程
dp[i][j]+=dp[i-1][j+2] * (C(j+2,2)) 代表从j+2个奇点中选2个连一条边
dp[i][j]+=dp[i-1][j-2] * (C(n-j+2,2)) 代表从n-j+2个非奇点中选两个连一条边
dp[i][j]+=dp[i-1][j] * ((j)*(n-j)) 代表从j个奇点和n-j个偶点中各选一个连边
但是到目前为止我们还没考虑去掉题目中禁止的重边问题。这里要用到容斥原理减去。
先说结果:dp[i][j]-=dp[i-2][j] * (C(n,2)-(i-2)) ,解释一下:因为n个点完全图上有n*(n-1)/2条边,dp[i-2][j]代表的是已经选的前i-2条边是没有重复的方案。那么到了i条边我们就得考虑减去第i条边与之前某一条边重复了那么第i条边有多少种选择(C(n,2)-(i-2)),那么重复的方案数就是 dp[i-2][j]*(C(n,2)-(i-2)) 。
对于这个重复数可能还是会有些疑惑:例如为什么可选边是C(n,2)-(i-2),因为其实通过开始的三条方程计算得到的结果会包含n点完全图的任一条边且此时选的第i条边会与每一条边重合,换句话来说就是只计算完前3条方程时候第i条边的方案数是不加任何限制能任意重合的,那么我们也就要减去第i条边的任意必重合方案。
综合上面4条就得到状态转移方程了,但是要注意上面的方程是带有顺序的,但是题目要求方案数是没有顺序的,所有dp[i][j]/=i。
HDU-5072 补集转化+容斥原理
题意:抽象起来核心问题就是在完全图上求同色/异色三角形数量。
解法:这道题很有意思值得一做,解法我曾经写过https://www.cnblogs.com/clno1/p/11490374.html。
- #include<bits/stdc++.h>
- using namespace std;
- const int N=1e5+;
- int n,m,a[N],mul[N],e[N];
- vector<int> fac[N];
- void prework() { //预处理1-100000的因子
- for (int i=;i<=;i++) {
- int n=i;
- for (int j=;j*j<=n;j++) {
- if (n%j==) {
- fac[i].push_back(j);
- while (n%j==) n/=j;
- }
- }
- if (n>) fac[i].push_back(n);
- }
- }
- int main()
- {
- prework();
- int T; cin>>T;
- while (T--) {
- scanf("%d",&n);
- for (int i=;i<=n;i++) scanf("%d",&a[i]);
- memset(mul,,sizeof(mul));
- memset(e,,sizeof(e));
- for (int i=;i<=n;i++) {
- int ALL=<<fac[a[i]].size();
- for (int j=;j<ALL;j++) {
- int sum=;
- for (int k=;k<fac[a[i]].size();k++)
- if (j&(<<k)) sum=sum*fac[a[i]][k];
- mul[sum]++; //代表是sum倍数的a[i]的个数++
- }
- }
- for (int i=;i<=n;i++) {
- int ALL=<<fac[a[i]].size();
- for (int j=;j<ALL;j++) {
- int sum=,sig=-;
- for (int k=;k<fac[a[i]].size();k++)
- if (j&(<<k)) sum=sum*fac[a[i]][k],sig*=-;
- e[i]+=sig*mul[sum]; //容斥原理求与a[i]不互质的数个数(包括自己)
- }
- e[i]=n-e[i]; //补集就是与a[i]互质的数个数(不包括自己)
- if (a[i]==) e[i]=n-;
- }
- long long ans=,tmp=;
- for (int i=n;i>n-;i--) ans=ans*i;
- ans=ans/; //计算全集C(n,3)
- for (int i=;i<=n;i++) tmp+=(long long)(e[i])*(n-e[i]-); //计算异色三角形数量
- printf("%lld\n",ans-tmp/);
- }
- return ;
- }
容斥原理+补集转化+MinMax容斥的更多相关文章
- [模板] 容斥原理: 二项式反演 / Stirling 反演 / min-max 容斥 / 子集反演 / 莫比乌斯反演
//待更qwq 反演原理 二项式反演 若 \[g_i=\sum_{j=1}^i {\binom ij} f_j\] , 则有 \[ f_i=\sum_{j=1}^i (-1)^{i-j} {i \ch ...
- luoguP3175 [HAOI2015]按位或 min-max容斥 + 高维前缀和
考虑min-max容斥 \(E[max(S)] = \sum \limits_{T \subset S} min(T)\) \(min(T)\)是可以被表示出来 即所有与\(T\)有交集的数的概率的和 ...
- BZOJ4036 [HAOI2015]按位或 【minmax容斥 + 期望 + FWT】
题目链接 BZOJ4036 题解 好套路的题啊,,, 我们要求的,实际上是一个集合\(n\)个\(1\)中最晚出现的\(1\)的期望时间 显然\(minmax\)容斥 \[E(max\{S\}) = ...
- Min-Max容斥及其推广和应用
概念 Min-Max容斥,又称最值反演,是一种对于特定集合,在已知最小值或最大值中的一者情况下,求另一者的算法. 例如: $$max(a,b)=a+b-min(a,b) \\\ max(a,b,c)= ...
- [luogu 3175] [HAOI2015]按位或(min-max容斥+高维前缀和)
[luogu 3175] [HAOI2015]按位或 题面 刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行按位或运算.问期望多少秒后,你手上的数字变成2^n ...
- bzoj4036 [HAOI2015]按位或 状压DP + MinMax 容斥
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4036 题解 变成 \(2^n-1\) 的意思显然就是每一个数位都出现了. 那么通过 MinMa ...
- min-max容斥学习笔记
min-max容斥学习笔记 前置知识 二项式反演 \[ f(n)=\sum_{i=0}^n\binom{n}{i}g(i)\Leftrightarrow g(n)=\sum_{i=0}^n(-1)^{ ...
- [总结] Min-Max容斥学习笔记
min-max 容斥 给定集合 \(S\) ,设 \(\max(S)\) 为 \(S\) 中的最大值,\(\min(S)\) 为 \(S\) 中的最小值,则: \[\max(S)=\sum_{T\in ...
- 「PKUWC2018」随机游走(min-max容斥+FWT)
「PKUWC2018」随机游走(min-max容斥+FWT) 以后题目都换成这种「」形式啦,我觉得好看. 做过重返现世的应该看到就想到 \(min-max\) 容斥了吧. 没错,我是先学扩展形式再学特 ...
随机推荐
- java类使用
package java04; /* * 通常情况下,一个类不能直接使用,需要创建一个对象,才能使用 * *步骤: * 1.导包:就是指出需要使用的类在什么位置 * import 包名称.类名称: * ...
- bzoj 1003物流运输 区间dp+spfa
基本思路: 一开始确实没什么思路,因为觉得怎么着都会超时,然后看一下数据范围,呵,怎么都不会超时. 思路: 1.看到能改变线路,想到可以用以下区间dp,区间dp的话,先枚举长度,枚举开始位置,然后枚举 ...
- u-tools图床便捷生成markdown图片
u-tools 图床 上传图片生成markdown图片非常便捷. 支持的图片服务器有几种,其中搜狗.网易和掘金的加载速度更快些: 也可以用阿里与和腾讯云的OSS; 其中网易生成图片不是原图尺寸好像被改 ...
- 09-排序2 Insert or Merge(25 分)
According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and gr ...
- BottomNavigationBar 自定义 底部导航条
在flutter中,BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,bottomNavigationBar是 Scaffold 组件的参数. BottomNav ...
- h5视频做背景的样式
video{ position: fixed; display: block; width: 100%; object-fit:fill; height:100%; right: 0px; botto ...
- AGC033 D~F——[ 值放到角标的DP ][ 思路+DP ][ 思路 ]
地址:https://atcoder.jp/contests/agc033/ D Complexity dp[ i ][ j ][ k ][ l ] 表示左上角是 ( i , j ) .右下角是 ( ...
- PPT技巧
1.秋叶个人的PPT三分钟教程 http://www.pptfans.cn/315656.html 2.<说服力-让你的PPT会说话>秋叶 3.<三体> https://w ...
- 前端每日实战:33# 视频演示如何用纯 CSS 创作牛奶文字变换效果
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/MGNWOm 可交互视频教程 此视频 ...
- 执行hbase zkcli命令报错
执行hbase zkcli后报错信息如下: 15/10/02 15:17:55 INFO zookeeper.ZooKeeper: Client environment:java.library.pa ...