NOIP2018模拟赛Potato
题目
分析
考虑动态规划。
首先考虑到产生一个
级土豆的条件是有两个
级的土豆。
由于每次都把土豆往左移,所以每次都是后面空出来一块盒子让你放。
于是可以Dp,先求当前一共有
个盒子,产生了一个
级土豆的概率。(接下来都假设有
个盒子)
考虑产生一个
级土豆,并且之后不再产生任何高于
级土豆的概率。
因为如果连一个
级土豆都没有产生的话,一定不会有更高级的土豆出现。
在此基础上,求最终第
个位置上是
级土豆,
内的所有土豆等级和的期望。
其中
表示的是加权平均,也就是
也就是考虑
个位置上最终为
级别的土豆的期望:先产生一个
级别的土豆,之后都不在产生
级别的土豆,在此基础上乘上这个情况下之后所有土豆等级和的期望。
但是要特殊考虑一种情况,就是
,这种情况下
位置只能直接产生一个
级的土豆。
所以额外新建状态,
表示最开始放了一个
级的土豆,合成了
的土豆的概率,
表示之后都不再产生高于
级别的土豆。转移方程:
最终的答案是
转移的复杂度是
的,只能通过
然而不难发现,土豆等级越高产生的概率应该是指数级别下降的。所以考虑舍去大于某个等级的土豆(标解舍去的是50级以上的土豆)
这样的话,当
的时候
的转移方程是一模一样的,采用矩阵优化即可。
复杂度
代码
#include<bits/stdc++.h>
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
double a[52][52], b[52][52], s[52][52], f[52][52];
struct Maxtir {
double m[52][52];
Maxtir() {memset(m, 0, sizeof(m));}
double *operator[](int i) {return m[i];}
Maxtir operator * (Maxtir b) {
Maxtir c;
for(int i = 1;i <= 51; ++i)
for(int j = 1;j <= 51; ++j)
for(int k = 1;k <= 51; ++k)
c[i][j] += m[i][k] * b[k][j];
return c;
}
}A, B;
void Pow(int k) {B = A; for(;k; A = A * A, k >>= 1) if(k & 1) B = B * A;}
int main() {
freopen("potato.in","r",stdin);
freopen("potato.out","w",stdout);
int n = ri(); double r = 0, p1 = ri() / 1e9, p2 = 1 - p1;
for(int i = 1;i <= 50; ++i)
for(int j = 1;j <= 50; ++j) {
if(j == 1) a[i][j] += p1;
if(j == 2) a[i][j] += p2, b[i][j] += p2;
a[i][j] += a[i][j - 1] * a[i - 1][j - 1];
b[i][j] += b[i][j - 1] * a[i - 1][j - 1];
}
for(int i = 50; i; --i)
for(int j = 1;j <= 50; ++j)
a[i][j] *= (1 - a[i - 1][j]), b[i][j] *= (1 - a[i - 1][j]);
for(int i = 1;i <= 50; ++i) f[50][i] = i;
for(int i = 49; ~i; --i) {
for(int k = 2;k <= 50; ++k)
f[i][1] += f[i + 1][k] * b[50 - i][k], s[i][1] += b[50 - i][k];
for(int j = 2;j <= 50; ++j)
for(int k = 1;k < j; ++k)
f[i][j] += f[i + 1][k] * a[50 - i][k], s[i][j] += a[50 - i][k];
for(int j = 1;j <= 50; ++j)
(f[i][j] /= s[i][j]) += j;
}
if(n <= 51) {
for(int i = 1;i <= 50; ++i)
r += a[n][i] * f[51 - n][i];
return printf("%.10lf\n", r), 0;
}
A[1][51] = A[51][51] = 1;
for(int k = 2;k <= 50; ++k) A[1][k] += b[50][k] / s[0][1];
for(int j = 2;j <= 50; A[j][51] = j, ++j)
for(int k = 1;k < j; ++k)
A[j][k] += a[50][k] / s[0][j];
Pow(n - 52);
for(int i = 1;i <= 50; ++i) {
double s = 0;
for(int j = 1;j <= 50; ++j)
s += B[i][j] * f[0][j];
s += B[i][51];
r += s * a[50][i];
}
printf("%.10lf\n", r);
return 0;
}