HDU4624Endless Spin(clj计数ppt)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4624
题意:总共有n个球,每次随机选择一段区间染黑(每段区间被选择的概率相同),求期望多少次所有球都被染黑。

分析:虽然ppt中说显然,但我认为这个问题最为精妙的地方就在第一步:

=i=1p[i]
,其中 p[i] 为i次之后仍然存在白球的概率。
这个公式怎么来的呢?直观的理解就是假如当前还有白球,那么必然还要染一次,而这一次对整体期望的贡献就是p[i].这之后就是传统的处理方法,枚举哪些球是白球,那么可以染黑的区间是固定的,由于这当中会有重复计算,只需要把奇数个白球的情况减去偶数个白球的方案数就是总的方案数,这种容斥方法在后面的Substring Pairs一题中也有体现。
另外,这题要保留15位小数,要用java才能通过。
java进行文件读写,可以使用Printwriter来做写操作,不过要记得close.
java可以方便的使用printf;
java的BigDecimal进行divide操作时,要设置scale和舍入mode

附上java代码

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
public class Main
{
        public static void main(String[] args) throws FileNotFoundException 
        {
            File fp2=new File("/home/poursoul/J.out");
            PrintWriter cout=new PrintWriter(fp2);
            Long [][][]dp=new Long[55][2500][2];
            BigDecimal []rep=new BigDecimal[100];
            for(int i=0;i<60;i++)rep[i]=new BigDecimal("0");
            for(int i=0;i<55;i++)for(int j=0;j<2500;j++)for(int k=0;k<2;k++)dp[i][j][k]=new Long(0);
            dp[0][0][0]=(long)1;
            BigDecimal t1=new BigDecimal("1");

            for(int i=1;i<=51;i++)
            {
                for(int j=0;j1)/2;j++)
                {
                    for(int k=0;k<2;k++)
                    {
                        for(int ni=0;niint tot=i-ni-1;
                            tot=tot*(tot+1)/2;
                            if(j>=tot)
                               dp[i][j][k]+=dp[ni][j-tot][k^1];
                        }
                    }
                    Long tp=(long)i*(i-1)/2;
                    BigDecimal p=new BigDecimal(j).divide(new BigDecimal(tp.toString()), 50, BigDecimal.ROUND_HALF_UP);
                    Long tp2=dp[i][j][1]-dp[i][j][0];
                    rep[i-1]=rep[i-1].add(t1.divide(t1.subtract(p), 50, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(tp2.toString())));
                }
               dp[i][i*(i-1)/2][0]=new Long(1);
            }
            for(int n=1;n<=50;n++)
                cout.printf("\"%.15f\",\n",rep[n]);
            cout.close();
        }
}

你可能感兴趣的:(clj计数问题,java)