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?
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
题意:有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; }
HDU4038-Stone(思维题)