hdu 4038 Stone(贪心模拟)

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

Stone

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 2535    Accepted Submission(s): 633


Problem Description
Given an array of integers {xi}. Each time you can apply one of the following operations to the array:
1. Choose an integer x from the array, replace it with x+1.
2. Add a new integer 1 to the array.

Define p as the product of all integers in the set. i.e. p=x1*x2*x3*...
What's the maximum possible value of p after exactly M operations?
 

Input
First line is a integer T (T ≤ 100), the number of test cases.
The first line of each test case contains two integers N and M, the number of integers in the initial set, and the number of operations.
The second line is N integers xi initially in the set.
1 ≤ N ≤ 100000
0 ≤ M ≤ 10^18
-10000 ≤ xi ≤ 10000
 

Output
For each case, you should output “Case k: ” first, where k indicates the case number and counts from one. Then the maximum product mod 1000000007.
 

Sample Input
  
  
4 1 1 5 3 2 1 2 3 3 2 -1 2 3 3 1 -3 -3 -3
 

Sample Output
  
  
Case 1: 6 Case 2: 18 Case 3: 6 Case 4: -18
 

Source
分析见下:
/*
两种操作,1.将一个数字加上1  2.在一个数列后追加一个1 (反正就是和1相关!)
求经过m个操作后,整个数列最大的乘积。因为-10000 ≤ xi ≤ 10000,所以要考虑负数的个数问题,
如果负数的个数是奇数,那么就先把最大的负数不断加1,直到成为非负数,成不了非负数也能让乘积的绝对值变小。
现在假设它变成非负了。问题变成了偶数个负数的整数序列最大乘积问题,如果存在0,那么需要不断消灭0.
现在假设0也消灭完了,因为1-->2 倍率是2,2^2=4;2-->3 倍率是3/2,(3/2)(3/2)=9/4>2;3-->4 倍率是4/3,(4/3)(4/3)<2。
所以优先考虑用1操作改变1和2,若没有1和2了,
用一个操作集(1.operati+2.operati+1.operatio)来增大原来的乘积(*3).
假设当没有1和2时还剩下m操作,
if(m==1) 增大最小的正整数1,
if(m%3==0) 加入m/3个3。
if((m-1)%3==0)加入m/3-1个3,再加个4;(很重要)
if((m-2)%3==0) 加入m/3个3,再加个2。
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e5+10,inf=0x3f3f3f3f,mod=1000000007;
int x[maxn];
typedef long long LL;
LL get(LL n){
    LL ans=1;
    for(int i=0;i<n;i++){
        ans=ans*x[i]%mod;
    }
    return ans;
}
LL power(LL a,LL p){
    LL ans=1,temp=a;
    while(p){
        if(p&1) ans=ans*temp%mod;
        temp=temp*temp%mod;
        p>>=1;
    }
    return ans;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int t,ca=1;
    cin>>t;
    while(t--){
        LL n,m;
        while(cin>>n>>m){
             int negsum=0,f1=-inf,dex;
             for(int i=0;i<n;i++){
                 scanf("%d",&x[i]);
                 if(x[i]<0) negsum++;
                 if(x[i]<0&&f1<x[i]){
                     dex=i;
                     f1=x[i];
                 }
             }
             if(negsum&1){
                 if(-f1>=m){
                     x[dex]+=m;
                     printf("Case %d: %lld\n",ca++,get(n));
                     continue;
                 }
                 m+=x[dex];
                 x[dex]=0;
             }
             //int sum0=0,sum1=0,sum2=0;
             for(int i=0;i<n&&m>0;i++){
                 if(x[i]==0){  x[i]++;  m--;  }
             }
             for(int i=0;i<n&&m>0;i++){
                 if(x[i]==1){ x[i]++; m--;  }
             }
             int minx=inf;
             dex=0;
             for(int i=0;i<n&&m>0;i++){
                 if(x[i]==2){
                    x[i]++;  m--;
                }
                if(minx>x[i]&&x[i]>=0){
                    minx=x[i];
                    dex=i;
                }
             }
             if(m==1){
                  x[dex]++;
                  printf("Case %d: %lld\n",ca++,get(n));
                  continue;
             }
             if(m==2){
                  printf("Case %d: %lld\n",ca++,get(n)*2%mod);
                  continue;
             }
             if(m%3==0){
                  printf("Case %d: %lld\n",ca++,get(n)*power(3,m/3)%mod);
                  continue;
             }
             if((m-1)%3==0){
                  printf("Case %d: %lld\n",ca++,get(n)*power(3,m/3-1)%mod*4%mod);
                  continue;
             }
             if((m-2)%3==0){
                  printf("Case %d: %lld\n",ca++,get(n)*power(3,m/3)%mod*2%mod);
             }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值