概率DP
这就是一个乱搞题,暴力发现TLE了,然后看了看discuss里说可以矩阵加速,想了一会才想明白怎么用矩阵,分着算的啊。先算f[num[i]-1]之类的,代码太长了,还是找找规律吧。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include <string> #include <queue> using namespace std; #define eps 1e-8 int num[11]; int judge(double x,double y) { double t = x-y; if(t < 0) t = -t; if(t < eps) return 1; else return 0; } int main() { int i,j,n,maxz; double p,f1,f2; while(scanf("%d%lf",&n,&p)!=EOF) { maxz = 0; for(i = 0; i < n; i ++) { scanf("%d",&num[i]); maxz = max(num[i],maxz); } sort(num,num+n); if(num[0] == 1) { printf("0.0000000\n"); } else { f2 = 1; f1 = 0; for(i = 2; i <= maxz+1; i ++) { double t; for(j = 0;j < n;j ++) { if(num[j] == i) break; } if(j != n) { swap(f2,f1); f2 = 0; } else { t = f2; f2 = f2*p + f1*(1-p); f1 = t; } if(judge(f1,f2)) { for(j = 0;j < n;j ++) { if(num[j] > i) { i = num[j]-1; break; } } } } printf("%.7lf\n",f2); } } return 0; }
乱推推,题意看清楚。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> using namespace std; #define eps 1e-8 double dp[1001][1001]; int in[1001][1001]; double dfs(int w,int b) { double t; if(in[w][b]) return dp[w][b]; if(w == 0) return 0; t = w*1.0/(w+b); in[w][b] = 1; if(b >= 2) { if(b-2 > 0) return dp[w][b] = t + b*1.0/(w+b)*(b-1)/(w+b-1)*(b-2)/(w+b-2)*dfs(w,b-3) + b*1.0/(w+b)*(b-1)/(w+b-1)*w/(w+b-2)*dfs(w-1,b-2); else return dp[w][b] = t + b*1.0/(w+b)*(b-1)/(w+b-1)*w/(w+b-2)*dfs(w-1,b-2); } return dp[w][b] = t; } int main() { int n,m; scanf("%d%d",&n,&m); printf("%.9lf\n",dfs(n,m)); return 0; }
入门题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include <string> #include <queue> using namespace std; #define eps 1e-6 double dp[1001][1001]; double w[1001][1001][3]; int judge(double x) { if(x < 0) x = -x; if(x < eps) return 1; else return 0; } int main() { int m,n,i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i = 0;i < n;i ++) { for(j = 0;j < m;j ++) { for(k = 0;k < 3;k ++) scanf("%lf",&w[i][j][k]); } } dp[n-1][m-1] = 0; for(i = n-1;i >= 0;i --) { for(j = m-1;j >= 0;j --) { if(i == n-1&&j == m-1) continue; if(judge(w[i][j][0]-1)) continue; dp[i][j] = (dp[i][j+1]*w[i][j][1] + dp[i+1][j]*w[i][j][2] + 2)/(1-w[i][j][0]); } } printf("%.3lf\n",dp[0][0]); } return 0; }
硬做就行,取整符号,你认识吗...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include <cmath> using namespace std; #define eps 1e-8 double dp[20001]; int in[20001]; int c[101]; int n; double dfs(int x) { int i; if(in[x]) return dp[x]; double ans,t2; t2 = ((sqrt(5.0)+1))*0.5; ans = 0; for(i = 0;i < n;i ++) { if(x > c[i]) ans += (int)(t2*c[i]*c[i]); else ans += dfs(x+c[i])+1; } ans /= n; in[x] = 1; return dp[x] = ans; } int main() { int i,f; while(scanf("%d%d",&n,&f)!=EOF) { memset(in,0,sizeof(in)); for(i = 0;i < n;i ++) scanf("%d",&c[i]); printf("%.3lf\n",dfs(f)); } return 0; }
ZOJ 3380 Patchouli's Spell Cards
这个题,完全就是组合DP的感觉。
题意要求至少有l个,求反面,所有的数字都是0-l-1就行了。
dp[i][j] 前j种,放了i个位置,枚举当前颜色,放0到l-1种,这个问题就是m个位置,插入n个相同的数,以前做过,把n插板,然后从m+1个空里选。
用java第一次TLE了,记忆化了一下fun函数,就过了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import java.math.BigInteger; import java.util.Scanner; public class Main { static BigInteger c[][] = new BigInteger[101][101]; static BigInteger s[][] = new BigInteger[110][110]; static boolean in[][] = new boolean[110][110]; public static BigInteger gcd(BigInteger a, BigInteger b) { if (b.compareTo(BigInteger.valueOf(0)) == 0) return a; else return gcd(b, a.mod(b)); } public static BigInteger fun(int n, int m) { int minz, i; if(in[n][m]) return s[n][m]; if (n == 0 || m == 0) return BigInteger.valueOf(1); if (n < m + 1) minz = n; else minz = m + 1; BigInteger ans = BigInteger.valueOf(0); for (i = 1; i <= minz; i++) { ans = ans.add(c[m + 1][i].multiply(c[n - 1][i - 1])); } in[n][m] = true; return s[n][m] = ans; } public static void main(String args[]) { Scanner cin = new Scanner(System.in); BigInteger dp[][] = new BigInteger[101][101]; int i, j, k, n, m, l; for (i = 0; i <= 100; i++) { for (j = 0; j <= 100; j++) c[i][j] = BigInteger.valueOf(0); } for (i = 0; i <= 100; i++) c[i][0] = BigInteger.valueOf(1); for (i = 1; i <= 100; i++) { for (j = 1; j <= 100; j++) c[i][j] = c[i - 1][j - 1].add(c[i - 1][j]); } while (cin.hasNext()) { m = cin.nextInt(); n = cin.nextInt(); l = cin.nextInt(); if (l > m) { System.out.println("mukyu~"); continue; } for (i = 0; i <= m; i++) { for (j = 0; j <= n; j++) dp[i][j] = BigInteger.valueOf(0); } dp[0][0] = BigInteger.valueOf(1); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { for (k = 0; k < l; k++) { if (dp[i][j].compareTo(BigInteger.valueOf(0)) == 0) continue; if (i + k > m) continue; dp[i + k][j + 1] = dp[i + k][j + 1].add(dp[i][j] .multiply(fun(i, k))); } } } BigInteger ans = BigInteger.valueOf(n).pow(m); BigInteger res = BigInteger.valueOf(0); for (i = 1; i <= n; i++) { res = res.add(dp[m][i]); } BigInteger t = gcd(ans.subtract(res), ans); System.out.println(ans.subtract(res).divide(t) + "/" + ans.divide(t)); } } }
感觉是神题呢,这是咋推的,我想了半天,硬做来了个二维的...看别人的题解,直接一位搞定。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <string> using namespace std; int n,num; double dp[100010]; double dfs(int step,int m) { double ans; if(step == n) { return (m*1.0/num); } ans = (m*1.0/num)*(dfs(step+1,m-1) + 1); if(m != num) ans += (num-m)*1.0/num*dfs(step+1,m); return ans; } int main() { int m,i; // while(scanf("%d%d",&m,&n)!=EOF) // { // num = m; // printf("%.9lf\n",dfs(1,m)); // } while(scanf("%d%d",&n,&m)!=EOF) { dp[1] = 1; for(i = 2;i <= m;i ++) dp[i] = (1-dp[i-1])*dp[i-1] + dp[i-1]*(dp[i-1]-1.0/n); double ans = 0; for(i = 1;i <= m;i ++) ans += dp[i]; printf("%.10lf\n",ans); } return 0; }
跟省赛的题非常相似,所有的dp[i]都用o1[i]*dp[0]+o2[i]表示,最后就解出dp[0]来了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> using namespace std; double o1[600]; double o2[600]; int main() { int n,k1,k2,k3,a,b,c,i,j,k,u,t; scanf("%d",&t); while(t--) { scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c); for(i = n;i >= 0;i --) { o1[i] = 1.0/k1/k2/k3; o2[i] = 1; for(j = 1;j <= k1;j ++) { for(k = 1;k <= k2;k ++) { for(u = 1;u <= k3;u ++) { if(i+j+k+u > n) continue; if(j == a&&k == b&&u == c) continue; o1[i] += 1.0/k1/k2/k3*o1[i+j+k+u]; o2[i] += 1.0/k1/k2/k3*o2[i+j+k+u]; } } } } printf("%.10lf\n",o2[0]/(1.0-o1[0])); } return 0; }