Stone
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 2267 Accepted Submission(s): 568
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
题意:有n个数(n<=1e5),m次操作(m<=1e18),每次操作,可以将某一个数加1,也可以放1个1到原数列中,问操作完后,n个数的乘积最大是多少?
思路:分类讨论:
一.先看负数的奇偶性:
1.如果是奇数,那么看最小的负数的绝对值如果大于m那么答案就是将这个数加上m然后直接算乘积(因为这个时候选择增长的倍率每步都是最高的)。否则的话就将这个数变成0,然后就与2相同了.
2. 如果是偶数,那么,就像将当中的0变成1,因为此时的性价比最高,因为这时候乘积从0变成了整数,接下来就是把所有的1变成2,那么就会有其他选择,如现将1都变
成3,此时2步的增长率是3,而前者的2步的增长率4,是最高的。接下来就是把所有的2变成3,如果将2变成4,此时2步的增长率是2,而前者是9/4,性价比是最高的。(你如果这时候在处理负数的话,整个乘积更是再减少!)
二.这个时候只剩下大于等于3的正整数了(前提是m还是正的),这个时候就要考虑添1的性价比了,考虑到只添1是没有意义的,至少要添1加上1,添1加1的相当于2步的增长率为2,而如果你用这两步处理3的话,25/16 和 5/3明显要劣于添1加1,接下来的就是讨论花两步变成2,和花3步变成3哪个性价比高了, 就是比较 2^(m/2)和3^(m/3) ,
1.m是3的倍数,那么明显是后者高。
2.如果m%3 = 1,那么(m-4)是3的倍数,2^(m-4)/2小于 3^(m-4)/3, 剩下的4,明显2^2 > 3^4/3,也可以是(m-1)/3,此时的增长率是 3^(m-1)/3还有1个1,此时的选择是添1,或者给某个3加上1,那么和前者有什么区别?
3.如果m%3 = 2,那么(m-2)是3的倍数,2^(m-2)/2小于3^(m-2)/3,剩下的2,明显明显2^2/2 > 3^4/3,也可以是分别给2个3加上1,那么此时的增长率是 16/9,低于前者。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxn = 100000+10;
const int MOD = 1000000007;
const int inf = 1e9;
int num[maxn];
int n;
ll m;
int neg_cnt;
ll ans;
ll pow_mod(ll n,ll m){
ll ret = 1,tmp = n;
while(m>0){
if(m&1) ret = (ret*tmp)%MOD;
tmp = (tmp*tmp)%MOD;
m>>=1;
}
return ret;
}
void init(){
ans = 1;
neg_cnt = 0;
}
void input(){
scanf("%d%I64d",&n,&m);
for(int i = 0; i < n; i++){
scanf("%d",&num[i]);
if(num[i]<0) neg_cnt++;
}
sort(num,num+n);
}
void output(){
for(int i = 0; i < n; i++){
ans = (ans*num[i])%MOD;
}
printf("%I64d\n",ans);
}
void compute(){
for(int i = 0; i < n && m>0; i++){
if(num[i]==0){
++num[i];
--m;
}
}
for(int i = 0; i < n && m >0; i++){
if(num[i]==1){
++num[i];
--m;
}
}
for(int i = 0; i < n && m > 0; i++){
if(num[i]==2){
++num[i];
--m;
}
}
ll cnt_3;
if(m >= 2){
if(m%3==0){
cnt_3 = m/3;
ans = pow_mod((ll)3,cnt_3);
}else{
int remain = m%3;
if(remain==1){
cnt_3 = m/3-1;
ans = pow_mod((ll)3,cnt_3);
ans = (ans*4)%MOD;
}else{
cnt_3 = m/3;
ans = pow_mod((ll)3,cnt_3);
ans = (ans*2)%MOD;
}
}
}
if(m==1){
int absMin = inf,minIdx = 0;
for(int i = 0; i < n; i++){
if(num[i] != -1){
if(absMin > abs(num[i])){
absMin = abs(num[i]);
minIdx = i;
}
}
}
num[minIdx]++;
}
output();
}
void solve(){
if(neg_cnt&1){
int k = 0;
while(k<n&&num[k]<0) k++;
--k;
if(m+num[k]<=0){
num[k] += m;
output();
}else{
m += num[k];
num[k] = 0;
compute();
}
}else{
compute();
}
}
int main(){
int ncase,T=1;
cin >> ncase;
while(ncase--){
init();
input();
printf("Case %d: ",T++);
solve();
}
return 0;
}