存在加特林,存在
很有意思的一道题,和一般的朴素概率 DP 不尽相同。
前面的思路和其它题解差不多,主要细说一下最后推式子的步骤。
对于
也就是说考虑其原本处于第
写到这就不难发现这东西是存在后效性的,或者说不存在初值,但是仍然存在显然的
于是考虑扩展到
此时我们仔细想一下刚才的过程,不难发现意义就是我们每次只崩首位的人,崩完之后不移动枪,而是将整个圆排列对应旋转。
然后我们考虑对于中间的转移,不难想到对于
当然我们这东西是没有初值的,不能直接递推,但是共存在
考虑对于
令
这样我们可以用
注意需要特判
最终时间复杂度
xxxxxxxxxx65123
4567891011
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
2324
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 初稿