题意:从包中等概率抽取一个卡片,卡片上面有一个数字。不放回抽取,然后从第二次抽取开始,假设当前抽到的数字是x,上一次抽到的数字是y。那么:

  • if x<y, the game ends and you lose;
  • if x=y, the game ends and you win;
  • if x>y, the game continues.

然后求win的概率。

分析:考虑每个数字的贡献,只有个数大于等于2时才会有贡献。枚举这个数字为最后抽取的数字,那么在之前抽取到的数字只会比这个小,而且严格递增有序,假设当前数字为x,那么相当于是从前x-1个数字里面抽不重复的若干个,这个可以看作是一个背包。d[i][j]表示从前 i 个里面抽取 j 个的方案数是多少个。然后抽取 当前结尾数字x时,设x的个数是num[x]个,那么根据排列组合的知识可以知道方案数是num[x] * (num[x]-1),然后我们现在共抽取了2+j 个卡片,赢得了比赛,但是计算总概率时,我们的计算方法是:\(赢得的方案总方案数赢得的方案 \div 总方案数\),因为总方案是 n!,相当于把 n 个卡片每一个的可能都列了进去,所以当我们抽取了 2+j 个卡片赢得了比赛时,我们不能忽略后面 n-2-j个卡片的顺序。

综上,数字x的贡献是

\[sum[x] = num[x]*(num[x]-1)*\Sigma_{j=0}^{x-1}d[x-1][j] * (n-2-j)!\]

求出每个数字的贡献,就得到了赢得的方案数,然后除以\(n!\) 即可。注意所有的操作都是在取模操作下,所以除法运算要计算逆元。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5005;
const int mod = 998244353;
int n,a[N];
ll num[N],fac[N],dp[N][N];
ll quick_mod(ll a,ll b){ll res = 1;for(;b;b>>=1){if(b&1)res = res * a % mod;a = a * a % mod;}return res;
}
int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);num[a[i]]++;}fac[0] = 1;for(int i=1;i<=5004;i++)fac[i] = fac[i-1] * i % mod;dp[0][0] = 1;for(int i=1;i<=n;i++){dp[i][0] = 1;for(int j=1;j<=i;j++){dp[i][j] = (dp[i-1][j] + dp[i-1][j-1] * num[i])%mod;}}ll res = 0;for(int i=1;i<=n;i++){if(num[i] >= 2){for(int j=i-1;j >= 0;j--){res = (res + dp[i-1][j] * num[i] %mod * (num[i] - 1) %mod * fac[n-j-2] %mod )%mod;}}}printf("%lld\n",res * quick_mod(fac[n],mod-2)%mod);return 0;
}

官方题解方法

d[i][j]表示抽取了 j 个卡片,最后抽取的是数字为 i 的卡片时可以赢得的概率。如何计算d[i][j] 当然是把从 [i][j]状态转移出去的状态(具体转移到哪个是等概率的)的概率求和就可以了。

  • 第一种转移显然是继续拿一个 i 。然后这种方案赢得的概率是 \({cnt_i-1 \over n-j}\)
  • 第二种是拿数字大于 i 的(注意,一次转移只能拿一个)。所以这种方案赢得的概率是\(\Sigma_{k=i+1}^n{({cnt_k \over n-j} * d[k][j+1])}\)

所以\(d[i][j] = {1\over n-j} * ((cnt_i-1) + \Sigma_{k=i+1}^n(cnt_k * d[k][j+1]))\)

所以从后往前遍历,用一个数组维护\(\Sigma_{i=x}^n(cnt_i*d[i][j])\) 即可

温馨提示:公式很好懂,但是逆元你真的会用了吗?

#include<bits/stdc++.h>using namespace std;const int MOD = 998244353;
const int N = 5005;
//注意a是引用
void upd(int &a, int b){a += b;a %= MOD;
}
//防止爆int,然后又不用ll,所以用这个
int mul(int a, int b){return (a * 1LL * b) % MOD;
}
//快速幂
int bp(int a, int n){int res = 1;for(; n > 0; n >>= 1){if(n & 1) res = mul(res, a);a = mul(a, a);}return res;
}int getInv(int a){int ia = bp(a, MOD - 2);assert(mul(a, ia) == 1);return ia;
}int n;
int cnt[N];
int dp[N][N];
int sum[N][N];
int inv[N];//存逆元int main(){for(int i = 1; i < N; ++i)inv[i] = getInv(i);cin >> n;for(int i = 0; i < n; ++i){int x;cin >> x;++cnt[x];}cnt[0] = 1;//从后往前for(int x = n; x >= 0; --x)for(int y = n; y >= 0; --y){if(cnt[x] == 0){upd(sum[x][y], sum[x + 1][y]);continue;}int s = n - y;if(s <= 0){upd(sum[x][y], sum[x + 1][y]);continue;}upd(dp[x][y], mul(cnt[x] - 1, inv[s]));//加上贡献的第一项upd(dp[x][y], mul(sum[x + 1][y + 1], inv[s]));//第二项//维护sum[x][y]upd(sum[x][y], sum[x + 1][y]);upd(sum[x][y], mul(cnt[x], dp[x][y]));}cout << dp[0][0] << endl;return 0;
}

转载于:https://www.cnblogs.com/chd-acm/p/10831272.html

CF-1156F Card Bag相关推荐

  1. CF1156F. Card Bag

    CF1156F. Card Bag Solution 概率DPDPDP. 记cnticnt_icnti​表示有多少个aj=ia_j=iaj​=i,再把aia_iai​离散化. 令fi,jf_{i,j} ...

  2. CF Card Reader Test市面CF读卡器不完全测评

    市面读卡器不完全测评 数码相机需要sd卡或者cf卡,对于一张几十MB的图片,拷贝的速度和写入速度肯定有要求.同时对于拷贝时对系统的负载影响也至关重要.负责考个1GB,2GB, 你就只有看电视或者去玩p ...

  3. cf#401(Div. 2)B. Game of Credit Card(田忌赛马类贪心)

    题干: After the fourth season Sherlock and Moriary have realized the whole foolishness of the battle b ...

  4. CF专题(长安大学)

    来暂时总结下这几天的CF专题吧-后续还会更新- A - Ichihime and Triangle: Ichihime is the current priestess of the Mahjong ...

  5. SDHC (High Capacity SD Memory Card)

    引用ifrcn 的 I24~ SDHC (High Capacity SD Memory Card) 目前市场出现了一种新的闪存卡产品――SDHC,相信许多消费者对这一产品还并不是非常了解,也许已经被 ...

  6. SD miniSD microSD TF CF MMC XD-Picture卡 SDIO CE-ATA SDHC SDXC

    1.SD卡 2.miniSD 3.microSD 4.T-Flash卡 5.CF卡 6.MMC 7.XD-Picture卡 8.SDIO 9.CE-ATA 10.MMC与SD区别.MicroMMC与M ...

  7. 【解题报告】博弈专场 (CF 2000~2200)前五题

    [解题报告]博弈专场 (CF 2000+)前五题 A:Fox and Card Game | CF388C 题意 思路 代码 B:Berzerk | CF786A 题意 思路 代码 C:Ithea P ...

  8. U盘寿命软件的查询工具 Flash Drive/Card Tester

    FlashTester是一款支持查看U盘寿命软件的查询工具,Flash Drive/Card Tester 是U盘.SD,MMC,CF卡等USB移动存储设备检测工具. USB Flash Drive ...

  9. SD卡与SD卡座电路以及TF卡(Micro SD Card,原名Trans-flash Card(TF卡))插拔式卡座和自弹出的卡座的引脚定义详细

    Micro SD Card,原名Trans-flash Card(TF卡),2004年正式更名为Micro SD Card,由SanDisk(闪迪)公司发明,主要用于移动电话. 在Micro SD面市 ...

最新文章

  1. JavaScript深入之变量对象
  2. Mockito cannot mock/spy because : - final class 问题
  3. 如何在VB例程中接收自定义消息
  4. 从QQ进程内存中搜索出QQ号码
  5. java中的Sort函数,你值得看
  6. agv系统介绍_AGV地面控制系统介绍
  7. OpenstackNova-KVM性能调优
  8. 五款机房教学管理系统,你的教室安装了吗
  9. IP纯真数据库不同系统环境下版本
  10. 一招解决origin8 licience过期
  11. php密码如何用星号表示,输入密码显示星号的写法实例
  12. 【歪门邪道】Android中如何快速回到主页
  13. 根据起始时间,获取之间所有的时间(基于momentjs)
  14. java实现Word 文档形式的导出功能
  15. ChatGPT原理解析以及使用方法介绍
  16. CoffeeScript 的简介与代码实例
  17. nestjs listen EADDRINUSE: address already in use :::3000
  18. 绝不错过:各省驻京办秘制招牌菜!
  19. 批量修改本地文件.bat命令使用与node.js批量修改文件
  20. 灵动微新品封装SOP8单片机32位MM32F0010A6T

热门文章

  1. 聚奎中学2021高考成绩查询,江津2017全体高考考生的喜报
  2. 分布式视频编码对比实验中H.264/AVC Intra 模式与H.264/AVC Inter Motion模式分析
  3. java线程服务器_一台Java服务器跑多少个线程
  4. “拼多多优惠券”测试的套路,今天让你秒懂~
  5. 这12道经典性能测试人员面试题,你都见过哪几道?(下)
  6. python中for循环流程图_Javascript for循环_郭隆邦技术博客
  7. android 使用shell模拟触屏_Appium常用操作之「微信滑屏、触屏操作」
  8. 服务器搭建成虚拟空间,服务器搭建虚拟空间
  9. 输入三科成绩 C语言,C语言题,对我的程序找错修改。输入10个学生学号,三科成绩,求总成绩和平均分,并按成绩由高到低输出...
  10. mysql主祝福hi_MySql - GROUP BY 和 HAVING关键字