• 题解 洛谷 P2612 【[ZJOI2012]波浪】DP+高精


    题目描述

    题目传送门

    分析

    因为有绝对值不好处理,所以我们强制从小到大填数

    (f[i][j][p][o]) 为当前填到了第 (i) 个数,波动强度为 (j),有 (p) 个连续段并且两端的端点选了 (o) 个时的概率

    注意这里的连续段是强制规定的

    那么转移有五种:

    (1)、填的数单独成为一段并且不在整个区间的两个端点上

    (f[i+1][j-i*2-2][p+1][o]+=f[i][j][p][o]*(p+1-o))

    因为后面填在这个数两边的数一定比这个数大,所以这个数一定做负贡献

    之前一共有 (p) 段,可以填的位置有 (p+1)

    因为一个段如果在整个区间的两端的话,只能在它的一边填,还要减去 (o)

    (2)、填的数单独成为一段并且在整个区间的两个端点上

    (f[i+1][j-i-1][p+1][o+1]+=f[i][j][p][o]*(2-o))

    此时这个数只会做一次负贡献

    方案数为剩余的整个区间的端点的数量,即 (2-o)

    (3)、新填的数放在已有的连续段的一端并且不与其它连续段相邻

    (f[i+j][j][p][o]+=f[i][j][p][o]*(p*2-o))

    因为这个数一定做一次正贡献和一次负贡献,所以会抵消,总贡献不变

    每个连续段都有两个端点可以选,再减去已选整个区间的端点的数量

    (4)、新填的数放在已有的连续段的一端并且与其它连续段相邻

    (f[i+1][j+2*i+2][p-1][o]+=f[i][j][p][o]*(p-1))

    其实就是把两个端拼成了一个大段

    做两次正贡献

    (5)、新填的数放在已有的连续段的一端并且当前的数填到了整个区间的端点上

    (f[i+1][j+i+1][p][o+1]+=f[i][j][p][o]*(2-o))

    做一次正贡献

    因为题目要求保留的位数不一样

    所以,对于精度较低的测试点,可以用 (double)

    对于精度较高的测试点,我们可以手写高精度

    手写高精度浮点数其实就是先把整个数左移很多位

    然后进行正常的加、乘、除的操作

    最后要多少位再四舍五入取到多少位即可

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<iomanip>
    #define rg register
    const int maxn=105,maxm=8005,bas=2500,jz=10000000;
    int n,m,k,mmax;
    struct asd{
    	int num[10],len;
    	asd(){
    		memset(num,0,sizeof(num));
    		len=0;
    	}
    	friend asd operator +(const asd &A,const asd &B){
    		asd C;
    		C.len=std::max(A.len,B.len);
    		for(rg int i=0;i<C.len;i++){
    			C.num[i]+=A.num[i]+B.num[i];
    			if(C.num[i]>=jz){
    				C.num[i]-=jz;
    				C.num[i+1]+=1;
    			}
    		}
    		if(C.num[C.len]) C.len++;
    		return C;
    	}
    	friend asd operator *(const asd &A,const asd &B){
    		asd C;
    		for(rg int i=0;i<B.len;i++){
    			for(rg int j=0;j<A.len;j++){
    				C.num[i+j]+=B.num[i]*A.num[j];
    			}
    		}
    		for(rg int i=0;i<B.len;i++){
    			for(rg int j=0;j<A.len;j++){
    				if(C.num[i+j]>=jz){
    					C.num[i+j+1]+=C.num[i+j]/jz;
    					C.num[i+j]%=jz;
    				}
    			}
    		}
    		C.len=B.len+A.len;
    		while(C.num[C.len-1]==0 && C.len-1!=0) C.len--;
    		return C;
    	}		
    	friend asd operator /(const asd &A,const int B){
    		asd C,D;
    		D=A;
    		for(rg int i=D.len-1;i>=0;i--){
    			rg int haha=D.num[i]+D.num[i+1]*jz;
    			C.num[i]=haha/B;
    			D.num[i]=haha%B;
    			D.num[i+1]=0;
    			if(i==0 && D.num[i]>=B/2){
    				C.num[i]++;
    			}
    			if(C.len==0 && C.num[i]){
    				C.len=i+1;
    			}
    		}
    		while(C.num[C.len-1]==0 && C.len-1!=0) C.len--;
    		return C;
    	}
    	void read(int aa){
    		len=0;
    		while(aa){
    			num[len++]=aa%jz;
    			aa/=jz;
    		}
    		while(num[len-1]==0 && len-1!=0) len--;
    	}
    	void write(int aa){
    		rg int pd=0;
    		printf("0.");
    		for(rg int i=len-1;i>=0;i--){
    			if(aa-7>=0){
    				if(aa==7 && num[i-1]%1000000%10>=5) pd=1;
    				printf("%07d",num[i]+pd);
    				aa-=7;
    			} else {
    				if(aa==1 && num[i]/100000%10>=5){
    					pd=1;
    				}
    				if(aa){
    					printf("%01d",num[i]/1000000%10+pd);
    					aa--;
    				}
    				if(aa==1 && num[i]/10000%10>=5){
    					pd=1;
    				}
    				if(aa){
    					printf("%01d",num[i]/100000%10+pd);
    					aa--;
    				}
    				if(aa==1 && num[i]/1000%10>=5){
    					pd=1;
    				}
    				if(aa){
    					printf("%01d",num[i]/10000%10+pd);
    					aa--;
    				}
    				if(aa==1 && num[i]/100%10>=5){
    					pd=1;
    				}
    				if(aa){
    					printf("%01d",num[i]/1000%10+pd);
    					aa--;
    				}
    				if(aa==1 && num[i]/10%10>=5){
    					pd=1;
    				}
    				if(aa){
    					printf("%01d",num[i]/100%10+pd);
    					aa--;
    				}
    				if(aa==1 && num[i]%10>=5){
    					pd=1;
    				}
    				if(aa){
    					printf("%01d",num[i]/10%10+pd);
    					aa--;
    				}
    				if(aa){
    					printf("%01d",num[i]%10+pd);
    					aa--;
    				}
    				break;
    			}
    		}
    		printf("
    ");
    	}
    }g[2][maxm][maxn/2][3];
    asd anss;
    void solve1(){
    	mmax=n/2+1;
    	rg int now=1;
    	g[0][bas][0][0].num[6]=1;
    	g[0][bas][0][0].len=7;
    	for(rg int i=0;i<n;i++){
    		now^=1;
    		for(rg int j=0;j<maxm;j++){
    			for(rg int p=0;p<=mmax;p++){
    				for(rg int o=0;o<=2;o++){
    					g[now^1][j][p][o].len=0;
    					memset(g[now^1][j][p][o].num,0,sizeof(g[now^1][j][p][i].num));
    				}
    			}
    		}
    		asd haha;
    		for(rg int j=0;j<maxm;j++){
    			for(rg int p=0;p<=mmax;p++){
    				for(rg int o=0;o<=2;o++){
    					if(g[now][j][p][o].len){
    						if(j-2*i-2>=0){
    							haha.read(p+1-o);
    							g[now^1][j-2*i-2][p+1][o]=g[now^1][j-2*i-2][p+1][o]+g[now][j][p][o]*haha/(i+1);
    						}
    						if(o<2 && j-i-1>=0){
    							haha.read(2-o);
    							g[now^1][j-i-1][p+1][o+1]=g[now^1][j-i-1][p+1][o+1]+g[now][j][p][o]*haha/(i+1);
    						}
    						haha.read(p*2-o);
    						g[now^1][j][p][o]=g[now^1][j][p][o]+g[now][j][p][o]*haha/(i+1);
    						if(p && j+2*i+2<maxm){
    							haha.read(p-1);
    							g[now^1][j+2*i+2][p-1][o]=g[now^1][j+2*i+2][p-1][o]+g[now][j][p][o]*haha/(i+1);
    						}
    						if(o<2 && j+i+1<maxm){
    							haha.read(2-o);
    							g[now^1][j+i+1][p][o+1]=g[now^1][j+i+1][p][o+1]+g[now][j][p][o]*haha/(i+1);
    						}
    					}
    				}
    			}
    		}
    	}
    	for(rg int j=bas+m;j<=bas+(n+1)*n/2;j++){
    		anss=anss+g[now^1][j][1][2];
    	}
    	anss.write(k);
    }
    double f[2][maxm][maxn/2][3],ans;
    void solve2(){
    	mmax=n/2+1;
    	rg int now=1;
    	f[0][bas][0][0]=1.0;
    	for(rg int i=0;i<n;i++){
    		now^=1;
    		for(rg int j=0;j<maxm;j++){
    			for(rg int p=0;p<=mmax;p++){
    				for(rg int o=0;o<=2;o++){
    					f[now^1][j][p][o]=0;
    				}
    			}
    		}
    		for(rg int j=0;j<maxm;j++){
    			for(rg int p=0;p<=mmax;p++){
    				for(rg int o=0;o<=2;o++){
    					if(f[now][j][p][o]){
    						if(j-2*i-2>=0) f[now^1][j-2*i-2][p+1][o]+=f[now][j][p][o]*(p+1-o)/(i+1);
    						if(o<2 && j-i-1>=0) f[now^1][j-i-1][p+1][o+1]+=f[now][j][p][o]*(2-o)/(i+1);
    						f[now^1][j][p][o]+=f[now][j][p][o]*(p*2-o)/(i+1);
    						if(p && j+2*i+2<maxm)  f[now^1][j+2*i+2][p-1][o]+=f[now][j][p][o]*(p-1)/(i+1);
    						if(o<2 && j+i+1<maxm) f[now^1][j+i+1][p][o+1]+=f[now][j][p][o]*(2-o)/(i+1);
    					}
    				}
    			}
    		}
    	}
    	for(rg int j=bas+m;j<=bas+(n+1)*n/2;j++){
    		ans+=f[now^1][j][1][2];
    	}
    	std::cout<<std::fixed<<std::setprecision(k)<<ans<<std::endl;
    }
    int main(){
    	std::cin>>n>>m>>k;
    	if(k<=8) solve2();
    	else solve1();
    	return 0;
    }
    
    
  • 相关阅读:
    localStorage用法
    es6写法
    div滚动条
    搜索框聚焦和失焦
    初步理解前端模块化开发
    clam安装
    div行高不确定,文字和图片居中
    html页面设置<span>的高度和宽度
    一款好用的wangEditor编辑器
    3月23 防360网页的示意图
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14056683.html
Copyright © 2020-2023  润新知