PTA印章
一、题目描述
二、解题思路
这题是一个概率DP题,我们考虑三种情况
我们用dp[i][j]代表i张印章能凑出j种,设p = 1 / n
显然第一种情况
当i<j时,dp[i][j]=0,因为不可能凑出j种
第二种情况
当j = 1时,此时选出的i张里面都是某一种,概率是(p^i),又因为可能都是n中的同一种,故都需要乘上n,因此概率为(p^(i-1))
第三种情况
当不处于上述两种情况时
如果此时前i - 1张,凑出了j 种印章,但是我现在拿到的和前j种重复了,此时的概率为(j / n)
如果此时前i - 1张,凑出了j - 1种印章,但是我现在拿到不属于前j - 1种的概率是(n - j + 1) / n
故可以写出状态转移方程
if(i < j) dp[i][j] = 0;
else if(j == 1) dp[i][j] = pow(p,i - 1);
else dp[i][j] = dp[i - 1][j] * (j * 1.0 / n) + dp[i - 1][j - 1] * ((n - j + 1) * 1.0 / n);
三、代码实现
1 #include "bits/stdc++.h" 2 #define PII pair<int,int> 3 #define rep(i,z,n) for(int i = z;i <= n; i++) 4 #define per(i,n,z) for(int i = n;i >= z; i--) 5 #define ll long long 6 #define db double 7 #define vi vector<int> 8 #define debug(x) cerr << "!!!" << x << endl; 9 using namespace std; 10 //从某个串中把某个子串替换成另一个子串 11 string& replace_all(string& src, const string& old_value, const string& new_value) { 12 // 每次重新定位起始位置,防止上轮替换后的字符串形成新的old_value 13 for (string::size_type pos(0); pos != string::npos; pos += new_value.length()) { 14 if ((pos = src.find(old_value, pos)) != string::npos) { 15 src.replace(pos, old_value.length(), new_value); 16 } 17 else break; 18 } 19 return src; 20 } 21 inline ll read() 22 { 23 ll s,r; 24 r = 1; 25 s = 0; 26 char ch = getchar(); 27 while(ch < '0' || ch > '9'){ 28 if(ch == '-') 29 r = -1; 30 ch = getchar(); 31 } 32 while(ch >= '0' && ch <= '9'){ 33 s = (s << 1) + (s << 3) + (ch ^ 48); 34 ch = getchar(); 35 } 36 return s * r; 37 } 38 inline void write(ll x) 39 { 40 if(x < 0) putchar('-'),x = -x; 41 if(x > 9) write(x / 10); 42 putchar(x % 10 + '0'); 43 } 44 double dp[30][30]; 45 int main() 46 { 47 int n,m; 48 n = read(); 49 m = read(); 50 double p = 1.0 / n; 51 for(int i = 1;i <= m;i++){ 52 for(int j = 1;j <= n;j++){ 53 //如果i<j,说明此时i张印章一定不能凑出j种印章 54 if(i < j) dp[i][j] = 0; 55 //如果j==1,此时选出的i张里面都是某一种,概率是(p^i),又因为可能都是n中的同一种,故都需要乘上n,因此概率为(p^(i-1)) 56 else if(j == 1) dp[i][j] = pow(p,i - 1); 57 //如果当前选的和之前选出的j种是同一种,那么此时的概率为(j / n),因为n中里面选出前j种的概率为(j / n) 58 //如果当前选的和之前的不同,说明增加了一种,此时前面选了j - 1种,我们不选到前面j - 1种的概率为(n -(j - 1)) / n = (n - j + 1) / n 59 else dp[i][j] = dp[i - 1][j] * (j * 1.0 / n) + dp[i - 1][j - 1] * ((n - j + 1) * 1.0 / n); 60 } 61 } 62 cout << fixed << setprecision(4) << dp[m][n]; 63 return 0; 64 }
本文来自博客园,作者:{scanner},转载请注明原文链接:{https://home.cnblogs.com/u/scannerkk/}