题意: 开始有m个金币, 在接下来n天里, ACMeow可以花费ci金币去买一个物品, 也可以以ci的价格卖掉这个物品, 如果它有足够的金币, 每天可以买或卖很多次; 求它在第n天能获得的最大金币数.
分析: (1)如果序列是递增的, 设为c1, c2, c3, c4, ..., cn; 那么如果ACMeow直接在第一天买,最后一天卖, 那么它最后获得的金币数为
如果中间卖(ci)掉一次再买(cj), 最后获得的金币数为
显然ci / cj<= 1, 所以如果是递增序列, 直接在最小的时候买, 最大的时候卖即可.
(2) 如果序列是递减的, 不进行任何交易可以取得最优值
(3) 推广到一般情况, 我们将序列拆分成若干子序列, 假设序列为 1 5 8 5 2 4 6 2 , 可以拆分成1 5 8 | (8) 5 (2) | 24 6 | (6) 2, 通过观察可以发现只需在序列取得极小值的时候买, 在序列取到最大值的时候卖即可. 由于计算时数值较大且中间取模比较麻烦, 所以直接用Java的BigInteger计算比较方便.
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
int v = 1;
while(t-- > 0) {
int n = cin.nextInt();
BigInteger m = cin.nextBigInteger(), bg = new BigInteger("0");
long cc = cin.nextLong(), c = 0;
int f = 1;
for(int i = 1; i < n; i++) {
c = cin.nextLong();
if(c > cc && f == 1) {
bg = m.divide(new BigInteger(cc + ""));
m = m.mod(new BigInteger(cc + ""));
f = 0;
}
if(c < cc && f == 0) {
m = m.add(bg.multiply(new BigInteger(cc + "")));
f = 1;
}
cc = c;
}
if(f == 0) {
m = m.add(bg.multiply(new BigInteger(c + "")));
}
System.out.println("Case #" + v++ + ": " + m.mod(new BigInteger("1000000007")));
}
cin.close();
}
}