Maximum Minimum identity

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/84373478

一个叫做 m i n m a x min-max 容斥的东西

大概就是:
m a x ( a , b ) = a + b m i n ( a , b ) max(a,b)=a+b-min(a,b)
m a x ( a , b , c ) = a + b + c m i n ( a , b ) m i n ( b , c ) m i n ( a , c ) + m i n ( a , b , c ) max(a, b, c) = a + b + c - min(a, b) - min(b, c) - min(a, c) + min(a, b, c)

当求一个集合的 m a x max 值很复杂的时候,就可以用 M M I MMI 来转化成求 m i n min ,通常在计数 d p dp 或者概率期望中用到。


有两道例题:
昨天写的luogu3175
其实就用到了这个思想

样例就是这样算的:
t [ i ] t[i] 表示第 i i 位变成 1 1 的时间
E [ m a x ( t [ 0 ] , t [ 1 ] ) ] = E [ t [ 0 ] ] + E [ t [ 1 ] ] E [ m i n ( t [ 0 ] , t [ 1 ] ) ] E[max(t[0], t[1])] = E[t[0]] + E[t[1]] - E[min(t[0], t[1])]
E [ t [ 0 ] ] = 1 / P r [ 0 1 ] = 1 / ( 1 / 2 ) = 2 E[t[0]] = 1 / Pr[在一次操作中,第0位变成1的概率] = 1 / (1/2) = 2
E [ t [ 1 ] ] = 1 / P r [ 1 1 ] = 1 / ( 1 / 2 ) = 2 E[t[1]] = 1 / Pr[在一次操作中,第1位变成1的概率] = 1 / (1/2) = 2
E [ m i n ( t [ 0 ] , t [ 1 ] ) ] = 1 / P r [ 0 1 1 ] = 1 / ( 3 / 4 ) = 4 / 3 E[min(t[0], t[1])] = 1 / Pr[在一次操作中,第0位或第1位变成1的概率] = 1 / (3/4) = 4/3
2 + 2 4 / 3 = 8 / 3 = 2.66666667 2 + 2 - 4/3 = 8/3 = 2.66666667

E [ m i n ( t [ a ] , t [ b ] , t [ c ] . . . ) ] = E[min(t[a], t[b], t[c] ... )] =
1 / P r [ a b c . . . 1 ] = 1 / Pr[在一次操作中,第a位或第b位或第c位或...变成1的概率] =
1 / ( 1 P r [ a , b , c , . . . 1 ] ) = 1 / (1 - Pr[在一次操作中,第a, b, c, ...均没有变成1的概率]) =

a , b , c , . . . 1 ( a , b , c , . . . ) 第a, b, c, ...均没有变成1 等价于 操作的集合是 (全集 - {a, b, c, ...})的一个子集
( a , b , c , . . . ) 求出 (全集 - {a, b, c, ...}) 的所有子集的概率之和

然后就是用 F M T FMT 优化 d p dp 的过程了


第二道是hdu4624
是clj出的题!

同样也是用 M M I MMI 的想法,把 E [ m a x { S } ] E[max\{S\}] 转化成 T S ( 1 ) T + 1 × E [ m i n { T } ] ∑_{T∈S}(−1)^{|T|+1}\times E[min\{T\}]
就可以概率 d p dp 了,注意到:
最终有用的

  1. 集合大小奇偶性,决定正负
  2. 有多少个操作,可以操作到集合中的某一个点 / 有多少个操作,操作不到集合中的任意一个点

所以设 f [ i ] [ j ] [ k ] f[i][j][k] 表示
集合中选择了 i i 染成黑色,集合大小奇偶性是 j ( 0 , 1 ) j(0, 1) k k 个操作,操作不到任意一个点
f [ i ] [ j ] [ k ] f[i][j][k] 是集合选取的方案数。

有转移方程: f [ i ] [ j ] [ k ] > f [ l ] [ j   x o r   1 ] [ k + ( l i ) × ( l i 1 ) / 2 ] f[i][j][k] -> f[l][j\ xor\ 1][k + (l - i) \times (l - i - 1) / 2]
第三维是因为 l , r l,r 同时选到 i i l l 中间的任意一点都是操作不到任意一个点的

计算最终的期望结果的时候就是用方案数乘概率,因为枚举 i i 的子集时发现只有 p i p^i 变,是一个等比数列,最终贡献就是 1 ( 1 p ) \frac {1}{(1-p)}

因此只需大概 O ( 5 0 4 ) O(50^4) 预处理 f f 和最终期望结果,询问时 O ( 1 ) O(1) 回答

但是题目要求保留 15 15 位小数,貌似要用浮点高精度,好麻烦的样子就找标程拍了拍 q w q qwq

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 55
#define LL long long
using namespace std;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

int t,n;
LL f[maxn][2][5005];
double E[maxn];

inline void prework(){
	f[0][0][0]=1;
	for(int i=0;i<=50;i++)
		for(int k=0;k<=(i+1)*i/2;k++)
			for(int j=0;j<=1;j++)
				if(f[i][j][k]){
					for(int l=i+1;l<=50;l++)
						f[l][j^1][k+(l-i)*(l-i-1)/2]+=f[i][j][k];
				}
	for(int i=1;i<=50;i++)
		for(int j=0;j<=i;j++)
			for(int k=0;k<=j*(j+1)/2;k++){
				long double p=0;
				if(f[j][0][k]){
					p=1.0*(k+(i-j+1)*(i-j)/2)/(1.0*(i+1)*i/2);
					if(p==1.0) continue;
					E[i]-=1.0*f[j][0][k]/(1.0-p);
				}
				if(f[j][1][k]){
					p=1.0*(k+(i-j+1)*(i-j)/2)/(1.0*(i+1)*i/2);
					if(p==1.0) continue;
					E[i]+=1.0*f[j][1][k]/(1.0-p);
				}
			}
}

int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out2.txt","w",stdout);
	prework();
	t=rd();
	while(t--){
		n=rd();
		printf("%.5lf\n",E[n]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/84373478