HDU 4870Rating(推公式)

有关这个题的高斯消元的方法已经在我的另一篇博客中给出http://www.cnblogs.com/gj-Acit/p/3888382.html

这里介绍一个很吊的解法,复杂度降到了O(n),以下转自http://www.cnblogs.com/chanme/p/3861766.html

先考虑一场比赛的情况,定义dp[k]为当前为k分,要达到20分时的期望回合数。(令q=1-p)

那么显然有 dp[0]=1+p*dp[1]+q*dp[0] 化简得 dp[0]=1/p+dp[1]

               dp[1]=1+p*dp[2]+q*dp[0] 化简得 dp[0]=1/p+1/p^2+dp[2]

我们令  dp[0]=tk+dp[k] 那么tk就表示由0状态到达k状态所需的期望回合数。那么显然如果是要到达20分的话,答案就是t20

然后我们看   dp[k]=1+p*dp[k+1]+q*dp[k-2]  代入dp[0]=dp[k]+tk 就有

dp[0]=1/p+1/p*t[k]-(1-p)/p*t[k-2]+dp[k+1]  

所以  t[k+1]=1/p+1/p*t[k]-(1-p)/p*t[k-2]

边界条件是  t[0]=0,t[1]=1/p,t[2]=1/p+1/p^2  

知道这些就可以递推出所有需要的t[k]了。

现在我们来看如果有两个账号怎么破。首先我们必然是 (0,0)->(0,1)->(1,1)->(1,2)->(2,2)->(2,3)->(3,3)...

(0,0)->(0,1)需要的期望回合数是t[1]-t[0].  (0,1)->(1,1)需要的期望回合数是 t[1]-t[0]

(1,1)->(1,2)需要的期望回合数是t[2]-t[1].  (1,2)->(2,2)需要的期望回合数是 t[2]-t[1].

....

(18,18)->(18,19)需要的期望回合数是t[19]-t[18]. (18,19)->(19,19)需要的期望回合数是t[19]-t[18].  

(19,19)->(19,20)需要的期望回合数是t[20]-t[19]。

全部加起来的结果就是t[19]*2+t[20]-t[19].

所以最后的复杂度可以是线性的,而且理论上对于k个账号也是适用的,这样就可以避开了高斯消元的做法了。

好吊,体会到了退公式的重要性了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 1 #include <map>
 2 #include <set>
 3 #include <stack>
 4 #include <queue>
 5 #include <cmath>
 6 #include <ctime>
 7 #include <vector>
 8 #include <cstdio>
 9 #include <cctype>
10 #include <cstring>
11 #include <cstdlib>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 #define INF ((LL)100000000000000000)
16 #define inf (-((LL)1<<40))
17 #define lson k<<1, L, mid
18 #define rson k<<1|1, mid+1, R
19 #define mem0(a) memset(a,0,sizeof(a))
20 #define mem1(a) memset(a,-1,sizeof(a))
21 #define mem(a, b) memset(a, b, sizeof(a))
22 #define FOPENIN(IN) freopen(IN, "r", stdin)
23 #define FOPENOUT(OUT) freopen(OUT, "w", stdout)
24 template<class T> T CMP_MIN(T a, T b) { return a < b; }
25 template<class T> T CMP_MAX(T a, T b) { return a > b; }
26 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
27 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
28 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
29 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
30 
31 //typedef __int64 LL;
32 typedef long long LL;
33 const int MAXN = 255;
34 const int MAXM = 110000;
35 const double eps = 1e-12;
36 
37 double t[30];
38 
39 int main()
40 {
41     //FOPENIN("in.txt");
42     double p;
43     while(~scanf("%lf", &p))
44     {
45         t[0] = 0;
46         t[1] = 1 / p;
47         t[2] = 1 / p + 1 / p / p;
48         for(int i=3;i<=20;i++)
49         {
50             t[i] = 1 / p * t[i-1] + 1 / p - (1-p) / p * t[i-3];
51         }
52         double ans = 2 *t[19] + t[20] - t[19];
53         printf("%lf
", ans);
54     }
55     return 0;
56 }
原文地址:https://www.cnblogs.com/gj-Acit/p/3888390.html