hdu 4038 stone


http://acm.hdu.edu.cn/showproblem.php?pid=4038

这题的题意就是给一序列的数,有两种操作,一种是把序列中某个数的值加1,要么在序列中增添一个数为1,然后给出操作数,最后要求这些数的乘积最大,求出这个乘积。 做这个题要考虑的细节很多,首先要把负数的个数求出,如果为奇数,那么要把最大的那个负数尽量加到0,就相当于转化为偶数的情况了,然后负数就不用在管了,这时候,序列中如果有0的话,很显然他们相乘就是0,所以尽量把所有的0要变成1,之后,如果操作数还有剩余,就要尽量把所有的1变成2了,因为1在序列中是没有任何用处的,增加到2就是翻一番,用1个操作数达到这种效果是最划算的,之后如果操作数还有剩余,再把所有的2变成3,因为两个操作可以在序列中新增添一个2,也可以将两个2变为两个3,这样分析一下,明显是把两个2变为两个3更为划算,一个操作的时候显然也是把2变为3更划算,之后,如果操作数还有剩余,那么,当操作数为1的时候,很显然是加到最小的那个正数上比较划算,但是操作数大于1的时候,我们可以假设序列中有很多个3,那么3+1所获得的增幅是4/3,那么我们可以比较在序列中新增一个数和把这么些个3加1所造成的增幅,可以发现,2,3,4,5,6的时候在序列中新增一个数所造成的增幅是大于在3的基础上加1的,而且,所有数是可以被2和3以加法形式组成的,例如6=3+3,很明显,6拆成3和3所造成的增幅要比自己靠谱,所以我们尽量把操作数拆分为2或者3,但是是谁更优先呢? 我们可以发先,如果3*a=2*b,那么3^a一定大于2^b,所以,最优先的应该是3,所以,我们应该尽量往序列中加3,然后再加2,使3*a+2*b=操作数。代码如下 #include<stdio.h> #define N 100010 const __int64 max=99999999; __int64 a[N]; const __int64 mod=(__int64)1000000007; __int64 exp(__int64 a,__int64 num,__int64 mod) { if(num==0)return 1%mod; if(num%2==0) { __int64 x=exp(a,num/2,mod); return (x%mod)*x%mod; } else { __int64 x=exp(a,(num-1)/2,mod); return ((x%mod)*a%mod)*x%mod; } } int main() { int T,l,i,j; __int64 min,sum,three,two,n,m,k,k2; scanf("%d",&T); for(l=1;l<=T;l++) { scanf("%I64d%I64d",&n,&m); sum=0; min=-max; three=0; two=0; for(i=1;i<=n;i++) { scanf("%I64d",&a[i]); if(a[i]<0) {sum++; if(a[i]>min){min=a[i];k=i;} } } if(sum%2) { if(min+m>0) { m+=min; a[k]=0; } else { a[k]+=m; m=0; } } if(m>0) { for(i=1;i<=n;i++) { if(a[i]==0) { if(m>0) { a[i]++; m--; } else break; } } } if(m>0) { for(i=1;i<=n;i++) { if(a[i]==1) { if(m>0) { a[i]++; m--; } else break; } } } if(m>0) { for(i=1;i<=n;i++) { if(a[i]==2) { if(m>0) { a[i]++; m--; } else break; } } } if(m>0) { min=max; for(i=1;i<=n;i++) { if(min>a[i]) { min=a[i]; k2=i; } } if(m%3==0) { three+=m/3; } else { if(m%3==1) { if(m==1) { a[k2]++; m--; } else { three+=m/3-1;//两个2比一个3和1要大 two+=2; m=0; } } else { if(m%3==2) { three+=m/3; two++; m=0; } } } } __int64 temp=1; for(i=1;i<=n;i++) { temp=temp*a[i]%mod; } __int64 sum1=exp((__int64 )3,three,mod); __int64 sum2=exp((__int64 )2,two,mod); temp=temp*sum1%mod*sum2%mod; printf("Case %d: %I64d\n",l,temp%mod); } }

  

转载于:https://www.cnblogs.com/acSzz/archive/2012/04/07/2435704.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值