题目: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?
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
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;
}