EOJ Monthly 2018.4 (E.小迷妹在哪儿(贪心&排序&背包)
ultmaster 男神和小迷妹们玩起了捉迷藏的游戏。
小迷妹们都希望自己被 ultmaster 男神发现,因此她们都把自己位置告诉了 ultmaster 男神,因此 ultmaster 男神知道了自己去找每个小迷妹所要花的时间。
已知发现第 i 小迷妹得到的分数为 ai⋅tr(tr 为游戏剩余时间)。ultmaster 想知道他最多能拿多少分。
Input
第一行两个整数 n,T (1≤n≤105,1≤T≤300) 分别表示小迷妹数量,游戏总时间。
接下去 n 行,每行两个整数 ai,ti (1≤ai≤100,1≤ti≤300) 分别表示发现小迷妹的分数以及 ultmaster 男神发现小迷妹所需时间。
Output
一个整数,表示 ultmaster 在游戏中最多拿多少分。
Examples
input
2 10 2 5 1 6
output
10
input
3 5 5 4 1 1 10 6
output
5
Note
样例一:找到小迷妹一,找到后得分 2×(10−5)=10 分。
样例二:找到小迷妹一,找到后得分 5×(5−4)=5 分,之后再找到小迷妹二得分也是 0,所以最高得分 5 分。
最优子结构解释一下:这里的价值和时间顺序有关,所以我们排序,那么让价值高的先占据背包。然后剩下的空余背包再去DP。
(总之,如果遇到价值和时间无关的,无需多想。有关的,注意一下是否需要排序)。
至于验证,就根据不同的题划不等式就行了。。。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int dp[310],ans; struct in { int a,t; }s[100010]; bool cmp(in w,in v){ return w.a*v.t>v.a*w.t;} int main() { int N,T; scanf("%d%d",&N,&T); for(int i=1;i<=N;i++) scanf("%d%d",&s[i].a,&s[i].t); sort(s+1,s+N+1,cmp); for(int i=1;i<=N;i++){ for(int j=T-s[i].t;j>=0;j--) dp[j+s[i].t]=max(dp[j+s[i].t],dp[j]+(T-j-s[i].t)*s[i].a); for(int j=1;j<=T;j++) dp[j]=max(dp[j],dp[j-1]); } cout<<dp[T]<<endl; return 0; }
It is your time to fight!