【luogu CF277D】Google Code Jam(DP)

Google Code Jam

题目链接:luogu CF277D

题目大意

你有 T 的时间,要做 n 道题,每道题有部分分的分数以及它需要的时间,在变成正解能多出的分数以及需要的时间以及正解写挂的概率。
如果写挂了可以选择不提交,问你期望最大分数以及在这个最大分数下的期望最小罚时。
罚时是指最后一次提交代码的时间。

思路

首先不考虑罚时,那就是一个普通的背包,直接每个物品三种情况要么不写,要么写暴力,要么再试着写正解。
那正解额外多的期望分数就是 val2pi(这里 pi 是不挂的概率)

然后考虑这个罚时,那我们肯定是先把要写的暴力都写了,再用某种顺序来写正解。
而且要注意的是这个罚时不一定只跟最后一个写的正解有关,它可能后面的若干个正解都挂了,所以你要安排出一个顺序而不是单纯确定最后一个。

考虑排序的比较,那我们其实就是要让如果寄了,那个距离结束的时间要尽可能的长。
那就直接用这个比:
(1x.p)(1y.p)y.ti1+(1y.p)y.ti2>(1y.p)(1x.p)x.ti1+(1x.p)x.ti2
然后化简一下:
(1x.p)x.ti2/x.p<(1y.p)y.ti2/y.p

然后注意一下卡精度就好。

代码

#include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int N = 1565; const long double eps = 1e-15; int n, t; long double f[N], g[N];//g:f中ti2*(1-p)最大的 struct node { int va1, va2, ti1, ti2; long double p; }a[N]; bool same(long double x, long double y) { return fabs(x - y) < eps; } bool cmp(node x, node y) { // return (1.0 - x.p) * (1.0 - y.p) * y.ti1 + (1.0 - y.p) * y.ti2 > (1.0 - y.p) * (1.0 - x.p) * x.ti1 + (1.0 - x.p) * x.ti2; return (1.0 - x.p) * x.ti2 / x.p < (1.0 - y.p) * y.ti2 / y.p; } int main() { scanf("%d %d", &n, &t); for (int i = 1; i <= n; i++) { int va1, va2, ti1, ti2; double p; scanf("%d %d %d %d", &va1, &va2, &ti1, &ti2); scanf("%lf", &p); p = 1.0 - p; a[i] = (node){va1, va2, ti1, ti2, p}; } sort(a + 1, a + n + 1, cmp); for (int i = 1; i <= t; i++) f[i] = -1.0, g[i] = 0.0; for (int i = 1; i <= n; i++) { int va1 = a[i].va1, va2 = a[i].va2, ti1 = a[i].ti1, ti2 = a[i].ti2; long double p = a[i].p; //ti1->va1 //ti2->va2*p, ti2*(1-p) for (int j = t; j >= 0; j--) { if (j + ti1 <= t) { if (f[j + ti1] < f[j] + va1 || (same(f[j + ti1], f[j] + va1) && g[j] > g[j + ti1])) { f[j + ti1] = f[j] + va1; g[j + ti1] = g[j]; } } if (j + ti1 + ti2 <= t) { if (f[j + ti1 + ti2] < f[j] + va1 + p * va2 || (same(f[j + ti1 + ti2], f[j] + va1 + p * va2) && (1.0 - p) * (g[j] + ti2) > g[j + ti1 + ti2])) { f[j + ti1 + ti2] = f[j] + va1 + p * va2; g[j + ti1 + ti2] = (1.0 - p) * (g[j] + ti2); } } } } long double ans1 = -1.0, ans2 = 0.0; for (int i = 0; i <= t; i++) { if (f[i] > ans1 || (same(f[i], ans1) && 1.0 * i - g[i] < ans2)) { ans1 = f[i]; ans2 = 1.0 * i - g[i]; } } printf("%.10lf %.10lf", (double)ans1, (double)ans2); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_CF277D.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示