【数学题】【Codeforces 164 Div2 E】【Playlist】

【题目来源】http://www.codeforces.com/contest/268/problem/E

 

【个人体会】总算知道这个题目的正解了。。。借助了2位大神的力量(其实事实是我根本没出脑力,只打了个程序)。。。

 

【题目大意】有N首歌,每首歌喜欢的概率为P[I],每首歌的时间为L[I]。一共有N!种排列方式来录制这些歌曲,对于每种排列方式,这个人开始听,遇到喜欢的歌曲,会接着听下一首歌曲;遇到不喜欢的歌曲,会把在这首歌之前的所有喜欢的歌听一遍,之后再回头来接着听下一首歌曲。最后求出数学期望总时间最长的那个时间。

 

【题目分析】1.对于I和J这2个位置,倘若这个人喜欢I,并且不喜欢J,那么I这首歌将会被再听一遍。发生这件事情的概率是P[I]*(1-P[J]),这件事情将会产生L[I]*P[I]*(1-P[J])的数学期望时间加成。

      2.假设现在只有2个人I和J,那么若L[I]*P[I]*(1-P[J]) > L[J]*P[J]*(1-P[I]),则说明I带来的数学期望时间加成会更多,那么I应当放在开头,J放在末尾。

      3.对于人多的情况先考虑简单一点的,2个人相邻I和I+1,现在考虑是否要交换它们2个,

         如果I在前面那么,数学期望的加成是:

         (1-P[I])*(P[1]*L[1]+P[2]*L[2]+...+P[I-1]*L[I-1]) +  (1-P[I+1])*(P[1]*L[1]+P[2]*L[2]+...+P[I-1]*L[I-1]+P[I]*L[I]);

                    如果I+1在前面,那么,数学期望的加成是

                    (1-p[I+1])*(P[1]*L[1]+P[2]*L[2]+...+P[I-1]*L[I-1]) + (1-P[I])*(P[1]*L[1]+P[2]*L[2]+...+P[I-1]*L[I-1]+P[I+1]*L[I+1]);

       两式相减,最终取决于(1-P[I+1])*P[I]*L[I]和(1-P[I])*P[I+1]*L[I+1]的大小关系。

      4.(1-P[I+1])*P[I]*L[I]和(1-P[I])*P[I+1]*L[I+1]  等价于  P[I]*L[I]/(1-P[I])和P[I+1]*L[I+1]/(1-P[I+1])

      5.将P[I]*L[I]/(1-P[I])视为A[i],即I的比较函数。对于一个序列来说,倘若它有最大的数学期望值,那么A[i]必然是严格递减的,否则经过两两交换的方法,必然能使得总期望值最大。

 

【代码如下】

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cmath>
 7 #include <vector>
 8 #include <deque>
 9 #include <stack>
10 #include <queue>
11 #include <algorithm>
12 
13 //#define FILE_IO
14 #define DEBUG
15 
16 const int Maxn = 50005;
17 int N, A[Maxn];
18 double L[Maxn], P[Maxn], Sum[Maxn], Ans;
19 
20 using namespace std;
21 
22 bool Cmp(const int &i, const int &j)
23 {
24     return (P[i] * L[i] * (1 - P[j] / 100)) > (P[j] * L[j] * (1 - P[i] / 100));
25 }
26 
27 int main()
28 {
29     #ifdef FILE_IO
30     freopen("test.in", "r", stdin);
31     #endif // FILE_IO
32     scanf("%d", &N);
33     for (int i = 1; i <= N; ++i)
34     {
35         scanf("%lf%lf", &L[i], &P[i]);
36         A[i] = i;
37     }
38     sort(A + 1, A + 1 + N, Cmp);
39     for (int i = 1; i <= N; ++i)
40         Sum[i] = Sum[i - 1] + L[A[i]] * P[A[i]];
41     for (int i = 1; i <= N; ++i)
42         Ans += L[i] * 10000;
43     for (int i = 2; i <= N; ++i)
44         Ans += (100 - P[A[i]]) * Sum[i - 1];
45     cout << setprecision(12) << setiosflags(ios :: fixed) << Ans / 10000 << endl;
46     return 0;
47 }

 

posted on 2013-02-06 20:00  孤星ぁ紫辰  阅读(265)  评论(1编辑  收藏  举报

导航