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;
}