【五校联考6day2】er

题意

给你两个数,和k个操作,让你选一些操作分配给这两个数使得它们乘积最大。一共有三种操作:乘法,让一个数乘 a ;加法,让一个数加b;赋值,把一个数赋值为 c (只有最多一个这种操作)。
最后答案求其自然对数。(普及一下知识:x=aba,blog(x)=log(a)+log(b)

数据范围

对于20% 的数据,N = 1;
对于全部数据M,K ≤ 100;N ≤ 2,最多一个Type_i = 1。
输入数据中所有数不超过2000。

分析

贪心

首先我们会很自然地想到贪心,因为乘法没什么策略,都是尽量最后乘,而乘哪一个都不会影响答案。所以我们就关键去考虑加法即可。加法我们可以贪心地想把当前这两个数的最小值加上当前的数 x ,但是这样的贪心会错(求解!!)期望得分60~80分。

正解

我们也可以类似的想,我们枚举i,表示用了i个加法,那么再枚举一个数x表示用小于等于i个加法的值给第一个数(当然我们肯定要先排序加法,然后求前缀和 sum[i] ,而乘法也一样排序后前缀积 num[i] 且这个x是可以任选的前i个的,这样就改进了前面的贪心的问题),那么我们便可以知道另一个加了多少 sum[i]x ,再用 sum[i]x+a(x+b)num[ki] 比较答案。当然处理x是否可行就可以用背包判定。

代码:

#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);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值