题意:
就是给你n个物品,每个物品有耗时,总能量,每秒失去多少能量。然后问你最多能吃多少能量。题目保证,当吃一个物品时直接把总能量都吃完,不存在吃着耗着。
思考:
1.很明显这种题目就是, 肯定是要先排序的,这样dp更新的时候才能更优的去更新。直接选择两个物品,让先选第一个优于先选第二个,然后看看式子,如果有多种情况,排序的时候都枚举出来就可以了。
2.对于每个点要减去时间的花费,如果定义不超j肯定不行,无法知道过去了多少时间。所以定义dp[i][j]为,用到物品i,时间恰好为j,最大价值。
3.还有一个要注意的,就是说一个物品吃的时候,可以第一口就拿掉所有值,不用等吃完。意味着,总时间可以超过一个值,然后这个答案也是可以算上去的,但是算的时候不能更新到dp里面,只能更新到maxn里。但是这个题目没有给你时间限制,而是让你自己定义的,那么这样时间就是所有物品的总和,自然不会出现超过时间,即使有,也在前面更新了。所以,当时间m是题目给的值的时候,这个判断更新maxn就要有了。这种可以多选一个的,之前在upc做过。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;
struct node{
int a,b,c;
};
int T,n,m,k;
node va[N];
int dp[110][10010];
bool cmp(node A,node B) //多少种情况都列出来,让每种情况都先选的更优
{
int a1 = A.a,b1 = A.b,c1 = A.c;
int a2 = B.a,b2 = B.b,c2 = B.c;
int sum1 = b2-a1*c2,sum2 = b1-a2*c1;
if(sum1!=0&&sum2!=0) return c1*a2>c2*a1;
else if(sum1==0&&sum2!=0) return a2*c1>b2;
else if(sum1!=0&&sum2==0) return b1>a1*c2;
else return b1>b2;
}
int solve()
{
m = n*100;
mem(dp,-0x3f); //定义恰好时,记得初始化
for(int i=0;i<=n;i++) dp[i][0] = 0;
int maxn = 0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
dp[i][j] = dp[i-1][j];
if(j>=va[i].a)
dp[i][j] = max(dp[i][j],dp[i-1][j-va[i].a]+max(0ll,va[i].b-va[i].c*(j-va[i].a)));
else if(j<m) maxn = max(maxn,dp[i-1][j]+max(0ll,va[i].b-va[i].c*j)); //这种就是即使超过了,还可以吃的,但是答案只能记在maxn里
}
}
for(int i=1;i<=n;i++) //恰好的定义方式要都更新一次,因为有的时间是组不成的
{
for(int j=0;j<=m;j++)
maxn = max(maxn,dp[i][j]);
}
return maxn;
}
signed main()
{
IOS;
cin>>T;
for(int cs=1;cs<=T;cs++)
{
cin>>n;
for(int i=1;i<=n;i++)
{
int a,b,c;
cin>>a>>b>>c;
va[i] = {a,b,c};
}
sort(va+1,va+1+n,cmp);
cout<<"Case #"<<cs<<": "<<solve()<<"\n";
}
return 0;
}
题意:
就是n个大臣,皇上始终排在最前面,然后每个人有个a和b,一个大臣获得的金钱就是,前面所有人的a的乘积/这个大臣的b。现在让你随便排序,问你获得最多金币的大臣最小为多少。
思考:
这是最经典的题目了。其实对于这种最大值最小啥的,一般就会去想二分,但是二分只有两种判断方式:一种是check贪心,一种是check判断可达性。一般check贪心的题目贪心也可以做,但是check贪心就是一种无脑判断,不用考虑那么多细枝末节。这题也不是可达性判断。推推式子,发现排序的公式就可以了。这题需要高精度,这里我就不写高精度了。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;
int T,n,m,k;
PII va[N];
int sum[N];
int maxn;
bool cmp(PII A,PII B)
{
return A.fi*A.se<B.fi*B.se;
}
signed main()
{
IOS;
cin>>n;
for(int i=0;i<=n;i++) cin>>va[i].fi>>va[i].se;
sort(va+1,va+1+n,cmp);
sum[0] = va[0].fi;
for(int i=1;i<=n;i++)
{
sum[i] = sum[i-1]*va[i].fi;
maxn = max(maxn,sum[i-1]/va[i].se);
}
cout<<maxn;
return 0;
}
题意:
就是给你n个牛,一个牛有重量和强壮度,然后这些牛叠罗汉,一个牛的压力值就是,上面所有牛的体重和-他自己的强壮度。现在让你随便排序,问你压力值最大的牛的最小值是多少。
思考:
其实这题就是和蓝桥杯国赛的搬砖一样,只是那个题再套了一层背包。这题也是推一下式子看看到底怎么是最优的,然后跑一遍就行了。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;
int T,n,m,k;
PII va[N];
int sum[N];
int maxn = -inf;
bool cmp(PII A,PII B)
{
return A.fi+A.se<B.fi+B.se;
}
signed main()
{
IOS;
cin>>n;
for(int i=1;i<=n;i++) cin>>va[i].fi>>va[i].se;
sort(va+1,va+1+n,cmp);
for(int i=1;i<=n;i++)
{
sum[i] = sum[i-1]+va[i].fi;
maxn = max(maxn,sum[i-1]-va[i].se);
}
cout<<maxn<<"\n";
return 0;
}
总结:
不论在什么比赛的时候,一定不要紧张乱想,就按平常心去做,像平时做题一样,把自己已知的各种算法结合起来去处理题目。