B3803 [NICA #1] 上大分 - 题解
通过数低?没有题解?那我来写一篇吧(B 题库的题都这么难了?)
题目大意
题目传送门
有
你预知了每场比赛打完后的表现分,设打比赛之前的比赛分为
写程序求出最高比赛分。
解题思路
先说一句,尽管题目没有明确说,打比赛的顺序是不能调换的(常识好吧),并且别忘了限制了参加场数。
简单的贪心是不凑效的,因为样例已经给出了一组先减分再加分的数据。容易发现难点在于 div 类型的处理。
如果不考虑 div2 限分,那么使用动态规划即可解决问题,令
而在加入类型之后,可以强制下分来打 div2,那么是否可以再维护小于
经过思考以后,我们发现,可以反过来设计状态,将题目的限制和要求的得分颠倒(经典的 DP 优化手段),变为“要达到一定的分数,至少需要打多少比赛”。于是我们令
而对 div2 的比赛,只需加上
由于比赛分不会超过
代码
值得一提的是,空间可以使用滚动数组优化,但此时需要注意更新顺序(类似 0-1 背包,每场比赛只能打一次,所以先更新靠近
#include<iostream>
#include<algorithm>
using namespace std;
int n,k,x,dp[4009],id,a;
int main() {
cin>>n>>k>>x;
for (int i=0;i<=4000;i++)
dp[i]=10009; //初设为 INF,大于 n 即可
dp[x]=0; //一场比赛都不打
while (n--) {
cin>>id>>a;
int m=4000; if (id==2) m=1899; //参与比赛的比赛分限制
for (int i=a+1;i<=m;i++) { //此处注意两个循环的遍历顺序
int now=i-(i-a+3)/4; //计算打完后的分数
dp[now]=min(dp[now],dp[i]+1); //试图更新
}
for (int i=min(m,a-1);i>=0;i--) {
int now=i+(a-i)/4;
dp[now]=min(dp[now],dp[i]+1);
}
}
for (int i=4000;i>=0;i--)
if (dp[i]<=k) { //找答案
cout<<i<<endl; break;
}
return 0;
}
本人第一篇题解,如有问题和建议欢迎指出!