概率DP 求期望,期望一般要逆推dp[i]代表已经正确打完前i个字符并且正确打完剩下的所有字母的期望,so dp[n] = 0,我们要求dp[0],题目让我们求最小,最小是因为他可以打不定字母再
去检测,具体多少不知道,对于dp[i],枚举j代表打了j个字母然后去检查,在枚举k,代表敲的j个字母,第k个是错误的,so对于不同的j,设敲了几个字母再去检查的期望为bj,
则dp[i] = min(b[j]),
其中bj = t+time // t是检查的时间,time是写这j个字符的时间,用前缀和即可
a[i+1]*(dp[i]+j*ts) // 第一个纠错了,因为是敲了j个再去检查,所以按删除键j次,然后就回到了正确打完前i个字符的情况
(1-a[i+1])*(a[i+2])*(dp[i+1]+(j-1)*ts) //第二个错了,回退j-1次,然后就回到了正确打完前i+1个字符的情况
....
(1-a[i+1])*....*(1-a[i+j])*(dp[i+j]) // j个字符全对了
注意等式左右都有dp[i],移项,在除一下就行了
by fd
1 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 double dp[111], a[111], b[111]; 7 int main() 8 { 9 int n; 10 double t, ts; 11 while(scanf("%d %lf %lf", &n, &t, &ts) != EOF) 12 { 13 for(int i = 1; i <= n; i++) 14 scanf("%lf", &a[i]); 15 for(int i = 1; i <= n; i++) 16 { 17 scanf("%lf", &b[i]); 18 b[i] += b[i-1]; 19 } 20 memset(dp, 0, sizeof(dp)); 21 for(int i = n-1; i >= 0; i--) 22 { 23 dp[i] = -1; 24 for(int j = 1; j+i <= n; j++) 25 { 26 double tmp = b[i+j]-b[i]+t+a[i+1]*ts*(j); 27 double tmp2 = 1; 28 for(int k = 1; k <= j+1; k++) 29 { 30 if(k > 1) 31 { 32 if(k == j+1) 33 tmp += tmp2*(dp[i+k-1]+ts*(j-k+1)); 34 else 35 tmp += tmp2*a[i+k]*(dp[i+k-1]+ts*(j-k+1)); 36 } 37 tmp2 *= (1-a[i+k]); 38 } 39 if(dp[i] < 0) 40 dp[i] = tmp/(1-a[i+1]); 41 else 42 dp[i] = min(dp[i], tmp/(1-a[i+1])); 43 } 44 } 45 printf("%.2lf\n", dp[0]); 46 } 47 return 0; 48 }
组合数+容斥 看到k很小就要往那里想,首先没有障碍物答案就是C(n+m, n)或C(n+m, m),然后减去不符合的,减去经过一个障碍物的,比如是x,y,那么相当于从0,0到x,y再从x,y到n,m。
然后加上经过2个障碍物的,减去经过3个障碍物的。。。。
by fd
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef __int64 LL; 6 const LL mod = 19992010; 7 struct node 8 { 9 int x, y; 10 }p[12]; 11 int n, m, k; 12 LL prime[2111], vis[2111], c; 13 LL pow_mod(LL a, LL b) 14 { 15 LL ans = 1; 16 while(b) 17 { 18 if(b&1) 19 { 20 ans *= a; 21 ans %= mod; 22 } 23 b >>= 1; 24 a *= a; 25 a %= mod; 26 } 27 return ans; 28 } 29 void init() 30 { 31 c = 0; 32 for(int i = 2; i <= 2000; i++) 33 { 34 if(!vis[i]) 35 { 36 prime[c++] = i; 37 for(int j = i*2; j <= 2000; j += i) 38 vis[j] = 1; 39 } 40 } 41 } 42 LL getnum(LL n, LL p) 43 { 44 LL sum = 0; 45 while(n) 46 { 47 sum += n/p; 48 n /= p; 49 } 50 return sum; 51 } 52 LL C(LL n, LL m) 53 { 54 LL ans = 1; 55 /*for(int i = 1; i <= m; i++) 56 { 57 ans *= (n-i+1); 58 ans /= i; 59 } 60 printf("***%I64d %I64d %I64d ", n, m, ans); 61 ans = 1; 62 */ 63 for(int i = 0; i < c && prime[i] <= n; i++) 64 { 65 LL x = getnum(n, prime[i]); 66 LL y = getnum(n-m, prime[i]); 67 LL z = getnum(m, prime[i]); 68 ans *= pow_mod(prime[i], x-y-z); 69 ans %= mod; 70 } 71 return ans; 72 } 73 74 bool cmp(node a, node b) 75 { 76 if(a.x != b.x) 77 return a.x < b.x; 78 return a.y < b.y; 79 } 80 81 void dfs(int i, int j, LL num, LL& ans, int cnt) 82 { 83 if(i == k+1) 84 { 85 if(cnt) 86 { 87 if(cnt&1) 88 { 89 ans -= num*C(p[i].x-p[j].x+p[i].y-p[j].y, p[i].x-p[j].x)%mod; 90 if(ans < 0) 91 ans += mod; 92 } 93 else 94 { 95 ans += num*C(p[i].x-p[j].x+p[i].y-p[j].y, p[i].x-p[j].x)%mod; 96 ans %= mod; 97 if(ans < 0) 98 ans += mod; 99 } 100 } 101 return; 102 } 103 if(p[i].x >= p[j].x && p[i].y >= p[j].y) 104 { 105 LL tmp = C(p[i].x-p[j].x+p[i].y-p[j].y, p[i].x-p[j].x)*num%mod; 106 dfs(i+1, i, tmp, ans, cnt+1); 107 } 108 dfs(i+1, j, num, ans, cnt); 109 } 110 int main() 111 { 112 init(); 113 int T; 114 scanf("%d", &T); 115 while(T--) 116 { 117 118 scanf("%d %d %d", &n, &m, &k); 119 for(int i = 1; i <= k; i++) 120 { 121 scanf("%d %d", &p[i].x, &p[i].y); 122 } 123 sort(p, p+k+1, cmp); 124 p[0].x = 0; 125 p[0].y = 0; 126 p[k+1].x = n; 127 p[k+1].y = m; 128 LL ans = C(n+m, n); 129 dfs(1, 0, 1, ans, 0); 130 printf("%I64d\n", ans); 131 } 132 return 0; 133 } 134 /* 135 5 136 1000 1000 5 137 1 1 138 2 2 139 5 5 140 100 100 141 98 555 142 143 1000 1000 4 144 1 1 145 5 5 146 100 100 147 98 555 148 */
枚举 DP当然可以搞,后来想到一中简单方法,枚举前2个位置有没有地雷,然后检测是否可行,答案最多4中,因为前面2个位置确定了,下面第二个位置雷的数量等于上面3个位置雷的数量之和,即x1+x2+x3 = y2,x1,x2是枚举的已经确定了,所以x3也确定了,然后x2和x3和y3推x4,推到最后,有矛盾退出。。
by fd