Endless spin

Endless spin

给你一段长度为[1..n]的白色区间,每次随机的取一个子区间将这个区间涂黑,问整个区间被涂黑时需要的期望次数。n<=50

这篇博客港的很好了,相信我没有什么好港的。注意这里的dp是第二种用法的dp。

#include <cstdio> 
using namespace std;

int T, n;
const int maxn=55;
long long f[maxn][2][maxn*maxn];

struct BigDouble{
	long long ip;  //整数部分 
	int a[maxn];
	BigDouble(){}
	BigDouble(long long x, long long y){
		ip=x/y; x=x%y;
		for (int i=0; i<maxn; ++i) x*=10, a[i]=x/y, x%=y; }
}E[maxn];
BigDouble operator+(const BigDouble &x, const BigDouble &y){
	BigDouble re; re.ip=x.ip+y.ip;
	for (int i=0; i<maxn; ++i) re.a[i]=x.a[i]+y.a[i];
	for (int i=maxn-1; i>0; --i) 
		if (re.a[i]>9) ++re.a[i-1], re.a[i]-=10;
	if (re.a[0]>9) ++re.ip, re.a[0]-=10;
	return re; 
}
BigDouble operator-(const BigDouble &x, const BigDouble &y){
	BigDouble re; re.ip=x.ip-y.ip;
	for (int i=0; i<maxn; ++i) re.a[i]=x.a[i]-y.a[i];
	for (int i=maxn-1; i>0; --i)
		if (re.a[i]<0) --re.a[i-1], re.a[i]+=10;
	if (re.a[0]<0) --re.ip, re.a[0]+=10;
	return re;
}
void print(BigDouble x){
	BigDouble y; if (x.a[15]>4) y.a[14]=1;
	y=y+x;
	printf("%lld.", y.ip);
	for (int i=0; i<15; ++i) printf("%d", y.a[i]); 
	puts(""); return; }

int main(){
	scanf("%d", &T);
	f[0][0][0]=1;
	for (int i=0; i<=50; ++i)  //当前考虑前i个数 ,第i个数是在集合内的 
		for (int j=0; j<=(i+1)*i/2; ++j){  // 区间个数为j 
			for (int k=i+1; k<=50; ++k)  //设第k个数 也在集合内 
				f[k][1][j+(k-i)*(k-i-1)/2]+=f[i][0][j];
			for (int k=i+1; k<=50; ++k)
				f[k][0][j+(k-i)*(k-i-1)/2]+=f[i][1][j];
		}
	int A, all;
	for (int i=1; i<=50; ++i)
		for (int j=0; j<=i; ++j){  //第j个数在子集内 
			for (int k=0; k<=(j+1)*j/2; ++k){  //k个区间 
				A=(k+(i-j+1)*(i-j)/2); all=(i*(i+1)/2);  //p=A/all;
				if (all==A) continue; 
				E[i]=E[i]-BigDouble(f[j][0][k]*all, all-A);
				E[i]=E[i]+BigDouble(f[j][1][k]*all, all-A);
			}
		}
	while (T--){ scanf("%d", &n); print(E[n]); }
	return 0;
}
posted @ 2018-09-06 15:47  pechpo  阅读(213)  评论(0编辑  收藏  举报