存在加特林,存在
很有意思的一道题,和一般的朴素概率 DP 不尽相同。
前面的思路和其它题解差不多,主要细说一下最后推式子的步骤。
对于
也就是说考虑其原本处于第
写到这就不难发现这东西是存在后效性的,或者说不存在初值,但是仍然存在显然的
于是考虑扩展到
此时我们仔细想一下刚才的过程,不难发现意义就是我们每次只崩首位的人,崩完之后不移动枪,而是将整个圆排列对应旋转。
然后我们考虑对于中间的转移,不难想到对于
当然我们这东西是没有初值的,不能直接递推,但是共存在
考虑对于
令
这样我们可以用
注意需要特判
最终时间复杂度
xxxxxxxxxx
651
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25template < typename T = int >
26inline T read(void);
27
28ld P;
29int N, K;
30ld dp[2][11000];
31
32int main(){
33 scanf("%Lf", &P), N = read(), K = read();
34 if(P < EPS)printf("%.10Lf\n", N == 1 ? (ld)1 : (ld)0), exit(0);
35 dp[1][1] = 1.0;
36 bool cur(false);
37 for(int i = 2; i <= N; ++i){
38 ld K(1.0), B(0.0), base1(1.0), base2(0.0);
39 for(int j = 2; j <= i; ++j)
40 base1 *= (1 - P), base2 = base2 * (1 - P) + P * dp[cur ^ 1][j - 1],
41 K += base1, B += base2;
42 dp[cur][1] = (1 - B) / K;
43 for(int j = 2; j <= i; ++j)
44 dp[cur][j] = (1 - P) * dp[cur][j - 1] + P * dp[cur ^ 1][j - 1];
45 cur ^= 1;
46 }printf("%.10Lf\n", dp[cur ^ 1][K]);
47 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
48 return 0;
49}
50
51template < typename T >
52inline T read(void){
53 T ret(0);
54 int flag(1);
55 char c = getchar();
56 while(c != '-' && !isdigit(c))c = getchar();
57 if(c == '-')flag = -1, c = getchar();
58 while(isdigit(c)){
59 ret *= 10;
60 ret += int(c - '0');
61 c = getchar();
62 }
63 ret *= flag;
64 return ret;
65}
update-2023_02_25 初稿