HDU4624 Endless Spin Min-Max容斥+DP

版权声明:这篇文章的作者是个蒟蒻,没有转载价值,如果要转说一下好了 https://blog.csdn.net/litble/article/details/83004089

题目分析

朋友,你听说过Min-Max容斥吗?

所谓Min-Max容斥就是这样一个式子: E ( m a x ( S ) ) = T S ( 1 ) S + 1 E ( m i n ( T ) ) E(max(S))=\sum_{T \subset S} (-1)^{|S|+1}E(min(T)) 。所谓的max,就是集合内最后一个被选中的元素被选中的期望代价,min就是第一个被选中的元素被选中的期望代价。

那么这题用一个Min-Max容斥,问题就转化为求每一个集合里的点,至少选中一个的期望。那么只要算出每一次决策一个都选不中的概率,也就是选择一次,选择的区间不包含这个集合里任何点的概率就行了。

复杂度 O ( 2 n ) O(2^n) ,你只需要把评测机换成神威太湖之光,就能AC此题。

设一个DP状态, f ( i , j , k , 0 / 1 ) f(i,j,k,0/1) ,表示考虑前 i i 个球是否在集合中,有 j j 个区间可以保证不选到在集合中的球,最后一个选择的球到 i i 位置之间有 k k 个空位,集合中选择的球的数量是偶数/奇数的状态数,转移通过考虑第 i + 1 i+1 个球选不选有两种:

f ( i + 1 , j , 0 , 1 / 0 ) + = f ( i , j , k , 0 / 1 ) f(i+1,j,0,1/0)+=f(i,j,k,0/1)
f ( i + 1 , j + k + 1 , k + 1 , 0 / 1 ) + = f ( i , j , k , 0 / 1 ) f(i+1,j+k+1,k+1,0/1)+=f(i,j,k,0/1)

这个DP是 O ( n 4 ) O(n^4) 的。

假设共有 i i 个球,某个集合 T T j j 个区间可以保证不选到在集合内的球,那么 E ( m i n ( T ) ) = ( i + 1 ) i 2 ( i + 1 ) i 2 j E(min(T))=\frac{\frac{(i+1)i}{2}}{\frac{(i+1)i}{2}-j} ,通过考虑集合内球数量的奇偶性,就可以做Min-Max容斥啦。

但是这题…尼玛保留15位小数。脑子有坑的litble打了一个高精度小数,并且在打完之后才意识到,应该打一个分数之间的运算,到最后再化成小数,算了,反正过了,就这样吧。

代码

#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef long long LL;
const int N=52,K=30;
struct QAQ{LL zs,xs[K+3];}ans[N];
LL f[N][N*N][N][2];
int T,n;
void print(QAQ a) {
	if(a.xs[16]>=5) ++a.xs[15];
	for(RI i=15;i>=2;--i) if(a.xs[i]==10) a.xs[i]=0,++a.xs[i-1];
	if(a.xs[1]==10) a.xs[1]=0,++a.zs;
	printf("%lld.",a.zs);
	for(RI i=1;i<=15;++i) printf("%lld",a.xs[i]);
	puts("");
}
QAQ getQAQ(LL fz,LL fm) {
	QAQ re; re.zs=fz/fm,fz%=fm,fz*=10;
	for(RI i=1;i<=K;++i) re.xs[i]=fz/fm,fz%=fm,fz*=10;
	return re;
}
QAQ operator + (const QAQ a,const QAQ b) {
	LL x=0;QAQ re;
	for(RI i=K;i>=1;--i)
		re.xs[i]=a.xs[i]+b.xs[i]+x,x=re.xs[i]/10,re.xs[i]%=10;
	re.zs=a.zs+b.zs+x;return re;
}
QAQ operator - (QAQ a,const QAQ b) {
	for(RI i=K;i>=2;--i) {
		if(a.xs[i]<b.xs[i]) a.xs[i]+=10,--a.xs[i-1];
		a.xs[i]-=b.xs[i];
	}
	if(a.xs[1]<b.xs[1]) a.xs[1]+=10,--a.zs;
	a.xs[1]-=b.xs[1],a.zs-=b.zs;
	return a;
}
QAQ mul(QAQ a,LL b) {
	LL x=0;
	for(RI i=K;i>=1;--i)
		a.xs[i]=a.xs[i]*b+x,x=a.xs[i]/10,a.xs[i]%=10;
	a.zs=a.zs*b+x;return a;
}
void prework() {
	f[0][0][0][0]=1;
	for(RI i=0;i<50;++i)
	  for(RI j=0;j<=i*(i+1)/2;++j)
		for(RI k=0;k<=i;++k)
		  for(RI t=0;t<=1;++t) {
		  	f[i+1][j][0][t^1]+=f[i][j][k][t];
		  	f[i+1][j+k+1][k+1][t]+=f[i][j][k][t];
		  }
	for(RI i=1;i<=50;++i)
	  for(RI j=0;j<i*(i+1)/2;++j) {
	  	QAQ tmp=getQAQ(i*(i+1)/2,i*(i+1)/2-j);
	    for(RI t=0;t<=1;++t) {
	    	LL js=0;
	    	for(RI k=0;k<=i;++k) js+=f[i][j][k][t];
	    	if(t) ans[i]=ans[i]+mul(tmp,js);
	    	else ans[i]=ans[i]-mul(tmp,js);
	    }
	  }
}
int main()
{
	scanf("%d",&T);
	prework();
	while(T--) scanf("%d",&n),print(ans[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/litble/article/details/83004089