题意
给你两个数,和k个操作,让你选一些操作分配给这两个数使得它们乘积最大。一共有三种操作:乘法,让一个数乘
a
;加法,让一个数加
最后答案求其自然对数。(普及一下知识:
数据范围
对于20% 的数据,N = 1;
对于全部数据M,K ≤ 100;N ≤ 2,最多一个Type_i = 1。
输入数据中所有数不超过2000。
分析
贪心
首先我们会很自然地想到贪心,因为乘法没什么策略,都是尽量最后乘,而乘哪一个都不会影响答案。所以我们就关键去考虑加法即可。加法我们可以贪心地想把当前这两个数的最小值加上当前的数 x ,但是这样的贪心会错(求解!!)期望得分60~80分。
正解
我们也可以类似的想,我们枚举i,表示用了i个加法,那么再枚举一个数
代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int cy,i,x,y,le,len,n,m,k,v[3],ma;
long long su,sum[105],a[105],b[105],f[200000];
double ans,a1,a2,a3,sec[105];
bool cmp(int x,int y){return x>y;}
void bag(int x){
fd(j,ma,x) f[j]=max(f[j],f[j-x]);
}
int main (){
scanf("%d %d %d",&n,&m,&k) ;
fo(i,1,n) scanf("%d",&v[i]);
fo(i,1,m) {
scanf("%d%d",&x,&y);
if (x==1) cy=y;else
if (x==2) a[++len]=y; else b[++le]=y;
}
sort(a+1,a+len+1,cmp);sum[0]=0;fo(i,1,len) sum[i]=sum[i-1]+a[i];ma=sum[len];
sort(b+1,b+le+1,cmp);sec[0]=0;fo(i,1,le) sec[i]=sec[i-1]+log(b[i]*1.0);
if (n==1) {
fo(i,0,len) {
if (i>k) break;
ans=max(ans,log(1.0*(sum[i]+v[1]))+sec[k-i]);
ans=max(ans,log(1.0*(cy+sum[i]))+sec[k-i-1]);
}
printf("%.3lf",ans);return 0;}
else {sec[0]=1;f[0]=1;
fo(i,0,len){
if (i>k) break;
bag(sum[i]-sum[i-1]);
if (k-i==le)
sum[0]=0;
fo(x,0,sum[i])
if ((f[x]>0)&&(f[sum[i]-x]>0)) {
su=sum[i]-x;
ans=max(ans,log((su+v[1])*1.0)+log((x+v[2])*1.0)+sec[k-i]);
ans=max(ans,log((su+v[1])*1.0)+log((x+v[2]+cy)*1.0)+sec[k-i-1]);
ans=max(ans,log((su+v[1]+cy)*1.0)+log((x+v[2])*1.0)+sec[k-i-1]);
}
}}
printf("%.3lf",ans);
}