Codeforces 1203F2 Complete the Projects (hard version)(dp)

啊,dp,万恶的dp。

本来不想补的,被某人押着说div3这么可以不ak于是不得不补了。真是痛苦的经历。(笑)

题目链接:https://codeforces.com/problemset/problem/1203/F2

题目大意:给定任务个数n和初始值r,完成每个任务需要有ai的r值,完成后r值会改变bi,问最多能完成多少任务(要保证最后r>=0)

思路:首先如果是正值的话自然按照a从小到大排一遍能加的都加上,然后问题在于负值。贪心显然不行,或者说这其实就是个背包问题的轻度转换,首先要做的预处理是对于bi为负值的第i项任务,它的ai=max(ai,-bi)这样才能保证完成这个任务后r不小于0,。然后就是dp,对于dp[i][j],我们认为它代表的是r值为j时,做到第i个任务为止(i已做)完成的最多任务数。那么,假设第i个能做,状态转移方程就是dp[i+1][j+aa[i].delt]=max(dp[i+1][j+aa[i].delt],dp[i][j]+1),aa储存的是所有的负值任务(已排序),这个方程的意思就是,假设能做,那就任务数+1,否则就在下个判断中补回这个任务消耗的r值。

代码如下:

 1 #include<set>
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<math.h>
 5 #include<vector>
 6 #include<stdlib.h>
 7 #include<queue>
 8 #include<algorithm>
 9 #include<map>
10 #include<stack>
11 using namespace std;
12 struct node
13 {
14     int ned;
15     int delt;
16     int zf;
17 }e[105];
18 bool cmp(node a,node b)
19 {
20     if(a.zf==b.zf)
21     {
22         if(a.zf==1)
23         {
24             return a.ned<b.ned;
25         }
26         else
27         {
28             return a.ned+a.delt>b.ned+b.delt;
29         }
30     }
31     return a.zf<b.zf;
32 }
33 int main()
34 {
35     int n,r;
36     scanf("%d%d",&n,&r);
37     for(int i=0;i<n;i++)
38     {
39         scanf("%d%d",&e[i].ned,&e[i].delt);
40         if(e[i].delt>=0)//标号1为正 2为负 便于一次性排序
41         {
42             e[i].zf=1;
43         }
44         else
45         {
46             e[i].zf=2;
47             e[i].ned=max(e[i].ned,abs(e[i].delt));
48         }
49     }
50     sort(e,e+n,cmp);
51     int s=r;
52     /*for(int i=0;i<n;i++)
53     {
54         printf("%d %d %d\n",e[i].ned,e[i].delt,e[i].zf);
55     }*/
56     int sum=0;
57     vector<node>aa;//储存负值任务
58     for(int i=0;i<n;i++)
59     {
60         if(e[i].zf==1)
61         {
62             if(s>=e[i].ned)
63             {
64                 s+=e[i].delt;
65                 sum++;
66             }
67         }
68         else
69         {
70             aa.push_back(e[i]);
71         }
72     }
73     vector<vector<int>>dp(aa.size()+1,vector<int>(s+1,0));
74     dp[0][s]=sum;
75     for(int i=0;i<int(aa.size());i++)
76     {
77         for(int j=0;j<=s;j++)
78         {
79             if(j>=aa[i].ned&&j+aa[i].delt>=0)
80             {
81                 dp[i+1][j+aa[i].delt]=max(dp[i+1][j+aa[i].delt],dp[i][j]+1);//假如当前任务可做
82             }
83             dp[i+1][j]=max(dp[i+1][j],dp[i][j]);//推到下一个任务
84         }
85     }
86     sum=0;
87     for(int i=0;i<=s;i++)
88     {
89         //printf("%d\n",dp[int(aa.size())][i]);
90         sum=max(sum,dp[int(aa.size())][i]);
91     }
92     printf("%d\n",sum);
93     return 0;
94 }

原文地址:https://www.cnblogs.com/forever3329/p/11370389.html

时间: 2024-08-28 20:41:24

Codeforces 1203F2 Complete the Projects (hard version)(dp)的相关文章

Codeforces 1203F2 Complete the Projects (hard version)

[cf题面](https://codeforces.com/contest/1203/problem/F2 Time limit 2000 ms Memory limit 262144 kB 解题思路 先留坑,吃完饭来填 源代码 #include<cstdio> #include<algorithm> int n,r; struct Data{ int need,delta; bool operator < (const Data & a)const{ if(delt

Codeforces 1203F1 Complete the Projects (easy version)

cf题面 Time limit 2000 ms Memory limit 262144 kB 解题思路 看见这题觉得贪心可做,那就贪吧.(昨天真是贪心的一天,凌晨才被这两道贪心题虐,下午多校又来,感觉我现在比赛时候想贪心就是瞎猜,猜出一个结论就想办法hack,想不出hack就交上去,然后WA,然后自闭,很难摸到门道) 下面这些是我的做题和思考过程-- 显然要先把能加rating和不掉rating的做了,而且要按照要求从低到高的顺序做,因为如果当前rating能满足要求高的,那也能满足要求低的,如

Codeforces 1172C2 Nauuo and Pictures (hard version) dp

Nauuo and Pictures (hard version 首先考虑简单版本的, 一个一个dp求出来, 分成三坨, 一坨当前要求照片, 一坨除了当前的喜欢的照片, 一坨除了当前的讨厌的照片. 单次dp   50 ^ 4 感觉hard的也挺简单的.. 我们先算出最后喜欢的照片的总w, 和讨厌的照片的总w, 然后每个的贡献就是在原先的w中所占的比例. #include<bits/stdc++.h> #define LL long long #define LD long double #de

CodeforcesF2. Complete the Projects (hard version) (贪心+贪心+01背包)

题目链接:传送门 思路: 对于对rating有提升的项目,肯定做越多越好,所以把$b_{i} >= 0$的项目按rating要求从小到大贪心地都做掉,得到最高的rating记为r. 对于剩余的$b_{i} < 0$的项目,因为r的范围很小,在6e4的亚子,可以考虑用01背包来做. 但是直接上01背包会WA,是因为不同项目选择的先后顺序会对结果有影响. 比如现在的r是5,有两个项目,(ai,bi)分别为(3,-3)和(3,-1),如果先做前面的项目,就会导致rating不够做后一个项目. 考虑任

Codeforces 235B Let&#39;s Play Osu! (概率dp求期望+公式变形)

B. Let's Play Osu! time limit per test:2 seconds memory limit per test:256 megabytes You're playing a game called Osu! Here's a simplified version of it. There are n clicks in a game. For each click there are two outcomes: correct or bad. Let us deno

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

CodeForces 258B Little Elephant and Elections 数位DP

前面先用数位DP预处理,然后暴力计算组合方式即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include

Codeforces 437E The Child and Polygon(区间DP)

题目链接:Codeforces 437E The Child and Polygon 题目大意:给出一个多边形,问说有多少种分割方法,将多边形分割为多个三角形. 解题思路:首先要理解向量叉积的性质,一开始将给出的点转换成顺时针,然后用区间dp计算.dp[i][j]表示从点i到点j可以有dp[i][j]种切割方法.然后点i和点j是否可以做为切割线,要经过判断,即在i和j中选择的话点k的话,点k要在i,j的逆时针方. #include <cstdio> #include <cstring&g

Codeforces 219D. Choosing Capital for Treeland (树dp)

题目链接:http://codeforces.com/contest/219/problem/D 树dp 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio&