最近刷洛谷,备战蓝桥杯,学到动态规划,感觉有些费解,遂写下自己的第一篇博客记录自己的思考过程,也督促自己学习。
# [蓝桥杯 2023 省 A] 填空问题
## 题目描述
## B. 有奖问答
小蓝正在参与一个现场问答的节目。活动中一共有 $30$ 道题目,每题只有答对和答错两种情况,每答对一题得 $10$ 分,答错一题分数归零。
小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要 $100$ 分,所以到达 $100$ 分时小蓝会直接停止答题。
已知小蓝最终实际获得了 $70$ 分对应的奖项,请问小蓝所有可能的答题情况有多少种?
## 提示
难度: 困难 标签: 2023, 省赛, 动态规划, DP
第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 A-B
思路:首先初学者小白最容易想到的就是模拟,暴力穷举每一中可能性(2的30次幂)
明显太费时间,不可取
因为答题是累加分数,答对+10,答错了归零。(注意分数等于100时会退出答题)
因此想到动态规划算法,即答完第 i 道题时的得分情况可以由第i - 1的情况推导出来
首先确定dp数组,初学可以用二维,方便思考
具体如下:
确定dp[i][j]的含义:答完前 i 道题目时得分为 j 的情况总数
确定初始条件:dp[1][10] = 1; dp[1][0] = 1;//所谓初始条件,就是答完第一题的得分情况
1.第 i 题答对:即dp[i][j] = dp[i-1][j-10];//因为如果题目答对,当前得分情况就是上一道题答完时的情况总数
2.第 i 题答错:即dp[i][0] = i-1题答完后各种得分的情况数总和,因为第i题答错了,则答完i - 1题时不管得分多少,都会清零。所以累加dp[i-1][ ]
思路总结完毕,下面写代码(本人比较懒,都用万能头加std)
#include<bits/stdc++.h>
using namespace std;
int dp[31][101];//空间开在main函数外,防止比赛内存溢出报错
int main()
{
dp[1][10] = 1;
dp[1][0] = 1;
long long ans = 0;
for(int i = 2; i <= 30; i++)//外层循环遍历题目(注意要从第二题开始,因为第一题已经定义了,而且从i=1开始会导致i-1为0,这种情况不存在),内层循环遍历得分情况
{
for(int j = 0; j <= 90; j = j + 10)//为什么不遍历到100分呢,因为题目说100分就停止答题了,所以不需要
{
if(j != 0)//如果第i题答对了
{
dp[i][j] = dp[i-1][j-10];
}
else if(j == 0)//如果第i题答错了,那么当前情况数(当前就得0分了)就是答完上一道题后所有得分的情况总和
{
//我们用循环累加
for(int k = 0; k <= 90; k = k + 10)
{
dp[i][0] += dp[i-1][k];
}
}
}
ans = ans + dp[i][70];
//为什么不在循环外面直接输出dp[30][70]呢?因为题目说过可以在任意时刻结束答题,所以我们ans加上在当前题目答完之后70分的情况数
}//如果最后输出dp[30][70],那表示的是答完30道题之后得70分的情况,但是我们有可能没有答完30题就已经得到70分了
cout << ans;
return 0;
}