【HDOJ】4043 FXTZ II

1. 题目描述
有n个球,第i个球的伤害值为$2^i-1, i in [1,n]$。有甲乙两个人,每次由甲选择n个球中的一个,用它以相同概率攻击自己或者乙,同时彻底消耗这个球。这样的攻击最多进行n次。
一旦甲的伤害值高于乙,则甲输,否则甲胜。问甲胜的概率是多少。

2. 基本思路
还是一步步推导。令dp[k]表示共有k个球时甲胜的概率。
egin{align}
    dp[1] &= frac{1}{2}    otag \
    dp[2] &= frac{1}{2} imes frac{1}{2} imes (1 + dp[1]) otag \
    dp[3] &= frac{1}{3} imes frac{1}{2} imes (1 + dp[1] + dp[2]) otag \
    dp[4] &= frac{1}{4} imes frac{1}{2} imes (1 + dp[1] + dp[2] + dp[3]) otag \
        &cdots otag \
    dp[n] &= frac{1}{n} imes frac{1}{2} imes (1 + Sigma_{i=1}^{n-1}dp[i])
end{align}
为什么上式成立,以$dp[3] = frac{1}{3} imes frac{1}{2} imes (1 + dp[1] + dp[2])$为例解释。
$frac{1}{3} imes frac{1}{2}$表示在第k次取到第3个球的概率(该球一定攻击乙),$k in [1,3]$。
此时,这个球一定属于乙(否则甲必输)并且从此时开始,无论后续的球如何安排,最终都是甲胜。
然而,前k次一定满足甲胜,否则在$[1,k-1]$的某一次中,即停止游戏。
当k=3时,概率为dp[2];
当k=2时,概率为dp[1];
当k=1时,概率为1。
以此类推,dp[n]。

3. 代码

 1 import java.lang.*;
 2 import java.io.*;
 3 import java.util.*;
 4 import java.math.BigInteger;
 5 
 6 
 7 public class Main {
 8     
 9     public static void main(String[] arg) throws java.lang.Exception {
10         InputStream inputStream = System.in;
11         OutputStream outputStream = System.out;
12         InputReader in = new InputReader(inputStream);
13         PrintWriter out = new PrintWriter(outputStream);
14         TaskA solver = new TaskA();
15         solver.solve(in, out);
16         out.close();
17     }
18 }
19 
20 
21     
22 class TaskA {
23     public final static int maxn = 505;
24     BigInteger[] FZ = new BigInteger[maxn];
25     BigInteger[] FM = new BigInteger[maxn];
26     
27     public TaskA() {
28         init();
29     }
30     
31     public void solve(InputReader in, PrintWriter out) {
32         int t = in.nextInt();
33         int n;
34         
35         while (t-- > 0) {
36             n = in.nextInt();
37             out.println(FZ[n].toString() + "/" + FM[n].toString());
38         }
39     }
40     
41     private void init() {
42         BigInteger sfm = BigInteger.ONE, sfz = BigInteger.ONE;
43         BigInteger fm, fz;
44         BigInteger g, lcm;
45         
46         for (int i=1; i<=500; ++i) {
47             fm = sfm.multiply(BigInteger.valueOf(i*2));
48             fz = sfz;
49             g = fz.gcd(fm);
50             FZ[i] = fz.divide(g);
51             FM[i] = fm.divide(g);
52             // System.out.println(fz + "/" + fm);
53             
54             g = sfm.gcd(FM[i]);
55             sfz = sfz.multiply(FM[i].divide(g))
56                      .add( FZ[i].multiply(sfm.divide(g)) );
57             sfm = FM[i].divide(g).multiply(sfm);
58         }
59     }
60     
61     private BigInteger A(int n, int m) {
62         BigInteger ret = BigInteger.ONE;
63         
64         for (int i=n; i>n-m; --i)
65             ret = ret.multiply(BigInteger.valueOf(i));
66         
67         return ret;
68     }
69 }
70 
71 class InputReader {
72     public BufferedReader reader;
73     public StringTokenizer tokenizer;
74     
75     public InputReader(InputStream stream) {
76         reader = new BufferedReader(new InputStreamReader(stream), 32768);
77         tokenizer = null;
78     }
79     
80     public String next() {
81         while (tokenizer==null || !tokenizer.hasMoreTokens()) {
82             try {
83                 tokenizer = new StringTokenizer(reader.readLine());
84             } catch (IOException e) {
85                 throw new RuntimeException(e);
86             }
87         }
88         return tokenizer.nextToken();
89     }
90     
91     public int nextInt() {
92         return Integer.parseInt(next());
93     }
94     
95     public long nextLong() {
96         return Long.parseLong(next());
97     }
98 }

 

原文地址:https://www.cnblogs.com/bombe1013/p/5236763.html