F - Lottery

2023-11-23 01:00
文章标签 lottery

本文主要是介绍F - Lottery,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门:ATC

正文:

此题是一道很妙的dp题。

总所周知,动态规划有两大难点,第一是想到这是一道dp题,第二是想到正确的状态转移方程

首先想聊聊怎么想到此题可以用dp来解:我们在想题目的时候,可以想往最暴力的方式去想,想想这题可不可以通过枚举求得正确答案,如果可以,那么此题就可能可以用dp求解,然后再想想不同项之间存不存在状态转移关系(一般想不出来),如果存在就是dp了。

回到此题,可以明显发现此题可以通过枚举状态来得到正确答案,所以我们的目标就变成找到状态转移式子。

题目给出三个变量 : n , m , k 。

题意可以用中文翻译成(原题是摸彩票,但我觉得没有涂颜色直观) : 一共有n种颜色,每种颜色有相应的出现概率,现在要在k张纸上涂色,问k张纸上有m种不同颜色的概率是多少?

我们先设dp[n][m][k]为答案(注意是先假设,在后面的分析中,其含义会改变)。

第一步:我们想一想dp[n][m][k] 和 dp[n][m][k - 1] 之间有没有一种联系。这种情况可以理解成加了一张纸,所以只要保证新加入的这张纸是m种颜色之一就行。

所以dp[n][m][k] = dp[n][m][k - 1] * (\sum _{i = 1} ^ mp(i))  其中p(i)只选择的第i号颜色出现的概率。

这个状态转移方程有没有用,我也不知道,我觉得应该没什么用,因为我无法确定我选择了哪m种颜色,所以这个方程不能直接转移,但是先不管那么多,先把方程列在这里罢了。

第二步:我们想一想dp[n][m][k] 和 dp[n][m- 1][k]之间有没有一种联系。这种情况不用多说,不用深入思考,就可以发现情况很复杂(以我的脑子肯定分析不来),所以直接就跳过吧。

第三步:我们想一想dp[n][m][k] 和 dp[n-1][m][k]之间有没有一种联系。这种情况可以直观的理解成加了一种选择的颜色。

可以分两种情况考虑了:

情况一:如果这个颜色我压根就不选,那么dp[n][m][k] = dp[n-1][m][k]

情况二:我选择了这个颜色,也就是说,纸张上的颜色要加一,即dp[n][m][k]dp[n-1][m][k]之间是不存在关系了,但是dp[n][m][k]dp[n-1][m-1][k]之间建立了新的联系。

我们进一步思考,如果加进去了新的颜色 c ,那么染成颜色c的纸张的个数明显会影响答案,我们假设新加入了kk张染有颜色c的纸, 现在的关键点就变成了处理dp[n][m][k]dp[n-1][m-1][k-kk] 之间的关系。

在之前,我们对dp的定义是答案。但现在要做出改变,这个改变我认为是此题最妙的点。

如果dp是答案的话,明显,这个结果是打乱了的,什么意思呢,我们假设现在有4张纸,有2种颜色(R and B),那么dp的结果应该是出现以下情况的概率之和:

RBBB,BRBB,BBRB,BBBR,RRBB,RBRB,RBBR,BRRB,BRBR,BBRR,RRRB,RRBR,RBRR,BRRR

如果这时候我们要在里面加一张纸,且这张纸的颜色不是R和B,显然,我们是无法对其进行去重的,也就是无法通过已有的方案数去确定所有可能的情况。

但是我们可以换一个角度去思考问题:

上面的所有可能一共可以分解成如下三种情况

一:RBBB 的所有排列组合=\frac{4!}{1!*3!}+\frac{4!}{2!*2!}+\frac{4!}{1!*3!}

二:RRBB的所有排列组合=\frac{4!}{2!*2!}

三:RRRB的所有排列组合=\frac{4! }{1!*3!}

 假设我们新加入p张染有颜色c的纸张,我们的方案数应该为:

\frac{(4+p)! }{1!*3!*p!}+\frac{(4+p)! }{2!*2!*p!}+\frac{(4+p)! }{1!*3!*p!}

这时候神奇的事情发生了,可见分子一定是纸张的个数的阶乘,而分子则是每种颜色的个数的阶乘。

如果我们以dp[n][m][k]*k! 为答案, dp[n][m][k]dp[n-1][m-1][k-kk] 之间就存在如下关系:

dp[n][m][k] =\frac{ dp[n-1][m-1][k-kk] * p(n) ^{kk} }{kk!}

因为kk是属于一个范围的,所以正确的状态转移方程可以写成:

dp[n][m][k] =\sum \frac{ dp[n-1][m-1][k-kk] * p(n) ^{kk} }{kk!}

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define  ll long long
const int mod = 998244353; 
ll ksm(ll a, ll b){ll kase = 1;while(b){if(b & 1){kase = kase * a % mod;}a = a * a % mod;b >>= 1 ;}return kase ;
}
ll ni(ll x){return ksm(x,mod-2);
}
ll dp[51][51][51];
int main(){ios::sync_with_stdio(false);cin.tie(0);int n , m ,k;cin>>n>>m>>k;vector<ll>w(n);for(int i = 0;i < n; i++){cin>>w[i];}ll sum = accumulate(w.begin(),w.end(),(ll)0);sum = ni(sum);for(int i = 0;i < n; i++){w[i] = w[i] * sum % mod; }vector<ll>fac(k+1);fac[0] = 1;for(int i = 1; i <= k;i++)fac[i] = fac[i -1 ] * i % mod;for(int i = 0 ; i <= n ;i++)dp[i][0][0]=1;for(int i = 1;i <= n;i++){for(int j = 1;j <= m ;j ++){for(int x = j ; x <= k;x++){for(int y = 0; y <= x - j + 1; y++){if(y == 0)dp[i][j][x] = (dp[i][j][x] + dp[i-1][j][x]) % mod;else {dp[i][j][x] += dp[i - 1][j - 1][x - y] * ksm(w[i - 1],y) % mod * ni(fac[y]) % mod;dp[i][j][x] %= mod;}}}}}cout<< dp[n][m][k] * fac[k] % mod<<'\n';return 0;
}

这篇关于F - Lottery的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/414198

相关文章

【数学】 HDU 1099 Lottery

HDU 1099 Lottery 题意没懂, 看了discuss,有人说的,才懂了。。。 #include <stdio.h>#include <iostream>#include <string>#include <cstring>using namespace std;__int64 gcd(__int64 a, __int64 b){if(b == 0) return

【攻防世界】lottery

弱比较+代码审计 本题已提供源码,如果没提供,输入/robots.txt,发现/.git  function buy($req){require_registered();require_min_money(2);$money = $_SESSION['money'];//接受用户原有money$numbers = $req['numbers'];//接受输入的数字$win_numbers =

Lottery Statistics

超级大乐透基本投注是指从前区号码中任选五个号码,并从后区号码中任选两个号码的组合进行投注。其中,前区号码由01—35共三十五个号码组成,后区号码由01—12共十二个号码组成。 一等奖:投注号码与当期开奖号码全部相同(顺序不限,下同),即中奖; 二等奖:投注号码与当期开奖号码中的五个前区号码及任意一个后区号码相同,即中奖; 三等奖:投注号码与当期开奖号码中的五个前区号码相同,即中奖; 从大乐透网

EX14 彩票中奖 (lottery.pas/c/cpp)

【题目描述】小明想试试运气去购买彩票,所以他开始研究彩票大乐透的玩法:超级大乐透是指由购买者从01—35共35个号码中选取5个号码为前区号码,并从01—12共12个号码中选取2个号码为后区号码组合为一注彩票进行的投注。每注金额人民币2元。小明打算用自己的零花钱去试试运气,选择了一组心目中的幸运数字,买了一张彩票。如下图:   两天后,中奖号码公布,小明开始研究到底中了多少奖金。获奖方式如上右图:

攻防世界-web-lottery

意思就是买彩票,中几个数字赚多少钱,按什么都要跳转到这个页面先注册   买一次2块钱,只允许输入7位数字 flag直接明码标价出售,但是要凑够9990000的钱(搏一搏,单车变摩托)  bp抓包看看  理论上修改点在numbers后面 去看看源码里面的api.php  这里的对比用了== php中==与===的区别 1.==只是对值得比较(将两边值转化为

攻防世界----lottery

知识点: 1.git泄露 2.php弱类型比较 拿到网址后,进行目录扫描 发现有git泄露  打开kali,用githack进行下载 拿到源码后进行代码审计   从index.php开始审计结合网站的买flag页面    去bug.php中发现了js的引用 在js中,发现了api.php     最终,在api.php中发现了分数的计算方式 注意到 那个

9. Lottery Scheduling

Lottery Scheduling 0. Basic Concept A : 75 tickets (0~74) B:25 tickets (75~99) A1 + A2:1000 tickets B1:10 tickets 注意:要区分一个进程和一个线程的tickets。 如下所示,A和B分别有100tickets,A中有两个需要处理的任务A1和A2,总共有1000tickets,每

攻防世界-web- lottery

lottery 41最佳Writeup由 清风77 提供WriteUP 收藏 反馈 难度:3 方向:Web 题解数:17 解出人数:5217 题目来源: XCTF 题目描述: 暂无 题目附件: 下载附件 题目场景: http://61.147.171.105:53991 100% 倒计时: 3时32分24秒 延时删除场景 题目已回答正确 近30天答题人数统计:

python | Incorrect lottery numbers 存储格式正确的彩票号码

Incorrect lottery numbers 存储格式正确的彩票号码 The file lottery_numbers.csv containts winning lottery numbers in the following format: 文件内容如下: Sample data week 1;5,7,11,13,23,24,30 week 2;9,13,14,24,34,35,3

攻防世界 lottery

打开页面发现是个彩票页面   发现需要注册,然后买彩票,得到足够的钱买flag